home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- ***
- *** Copyright (c) 1990 by Sun/Lucid, All Rights Reserved.
- *** Copyright (c) 1991-1993 by Lucid, Inc. All Rights Reserved.
- ***
- *****************************************************************************/
-
- /* Synched up with: Not in FSF. */
-
- #include <config.h>
-
- #ifdef ENERGIZE /* whole file */
-
- #include "lisp.h"
-
- /* Display Context for the icons */
- #include "device-x.h"
- #include "frame-x.h"
- #include <Xm/DialogS.h>
- #include "lwlib.h"
- #include "objects-x.h"
-
- #include "events.h"
- #include "opaque.h"
- #include "buffer.h"
- #include "extents.h"
- #include "process.h"
- #include "insdel.h"
- #include "window.h"
- #include "faces.h"
-
- /* Energize editor requests and I/O operations */
- #include "energize.h"
-
- #include "systime.h"
- #include "sysfile.h"
- #include "syssignal.h"
-
- #ifndef CBFileYourself
- /* This means that emacs is being compiled against the connection library
- and headers that go with an Energize protocol less than 0.10. We need
- to do some slightly different things in this file because of that.
-
- Note that if Emacs is compiled against the 3.0 version of the connection
- library and associated headers, it can still talk to 2.1- or 2.5-level
- servers. But the opposite is not true.
- */
- # define ENERGIZE_V2_HEADERS
- #endif
-
- /* The Connection library
- */
- extern void CWriteQueryChoicesRequest ();
- extern void CWriteExecuteChoicesRequest ();
- extern void CWriteSheetRequest ();
- extern void CWriteSetControlRequest ();
- extern void CWriteChoice ();
- extern void CWriteProtocol ();
- extern int CGetPortNumber ();
-
-
- /************** Typedefs and Structs ***********************/
-
- /* structure argument used by the next mapping function */
- typedef struct
- {
- BufferInfo *binfo;
- int n_extents;
- } binfo_and_n_extents;
-
- typedef struct
- {
- BufferInfo* binfo;
- int state;
- int tell_energize;
- } binfo_and_state;
-
- struct reply_wait
- {
- int serial;
- EId objectId;
- EId genericId;
- EId itemId;
- char answered_p;
- char status;
- char* message;
- Lisp_Object menu_result;
- Lisp_Object only_name;
- struct reply_wait* next;
- };
-
- static struct reply_wait *global_reply_wait;
-
- Lisp_Object Venergize_kernel_busy;
- Lisp_Object Qenergize_kernel_busy;
- Lisp_Object Venergize_attributes_mapping;
- int energize_extent_gc_threshold;
- Lisp_Object Venergize_kernel_busy_hook;
- Lisp_Object Qenergize_kernel_busy_hook;
- Lisp_Object Venergize_menu_update_hook;
- Lisp_Object Qenergize_menu_update_hook;
- Lisp_Object Qenergize;
- Lisp_Object Qenergize_auto_revert_buffer;
-
-
- static void set_energize_extent_data (EXTENT extent, void *data);
-
- static char *kernel_buffer_type_to_elisp_type (char *kernel_type);
-
- static CONST void *get_object (EId id, BufferInfo *binfo);
- static void put_object (EId id, BufferInfo *binfo, void *object);
- static void remove_object (EId id, BufferInfo *binfo);
- static void free_GDataclass (GDataClass *cl, BufferInfo *binfo);
-
- static void free_GenericData (GenericData *gen, BufferInfo *binfo);
-
- static void free_Energize_Extent_Data (Energize_Extent_Data *, BufferInfo *,
- enum Energize_Object_Free_Type);
-
- static BufferInfo *get_buffer_info_for_emacs_buffer (Lisp_Object emacs_buf,
- Editor *editor);
- static void put_buffer_info (EId id, Lisp_Object emacs_buf,
- BufferInfo *binfo, Editor *editor);
-
- static void handle_sheet_control_change (Widget, EId sheet_id, void* arg);
- static Connection *make_energize_connection (Editor *editor,
- int fdin, int fdout);
- static void close_energize_connection (void);
- Lisp_Object Fclose_connection_to_energize (void);
- static void mark_all_extents_as_unmodified (BufferInfo *binfo);
- Lisp_Object Fenergize_barf_if_buffer_locked (void);
- Lisp_Object Fconnected_to_energize_p (void);
- static int get_energize_connection_and_buffer_id (Lisp_Object buffer,
- void **conn_ptr,
- long *buffer_id_ptr);
-
- void restore_energize_extent_state (EXTENT);
-
-
- /**************************** Variables *****************************/
-
- /* debugging variable */
- int ignore_kernel;
-
- Lisp_Object Venergize_kernel_modification_hook;
- Lisp_Object Venergize_create_buffer_hook;
- Lisp_Object Qenergize_create_buffer_hook;
-
- Lisp_Object Qenergize_buffer_modified_hook;
- Lisp_Object Qbuffer_locked_by_energize;
- Lisp_Object Qenergize_user_input_buffer_mark;
- Lisp_Object Qenergize_make_many_buffers_visible;
-
- int inside_parse_buffer;
-
- /* List of all buffers currently managed by Energize. This is
- Staticpro'ed so that they don't get GC'ed from under us. */
- static Lisp_Object Venergize_buffers_list;
-
- static Editor *energize_connection;
- static protocol_edit_options *peo;
-
- static int request_serial_number;
-
- extern int current_debuggerpanel_exposed_p;
- extern int desired_debuggerpanel_exposed_p;
- extern int debuggerpanel_sheet;
-
- /**************************** Macros *****************************/
-
- #define xnew(type) ((type*)xmalloc (sizeof (type)))
-
- #define BUFFER_NOTIFY_BACKGROUND_BIT_SET_P(buffer) 1
-
- #define get_extent_data(id,binfo) (Energize_Extent_Data*)get_object(id, binfo)
- #define get_class(id,binfo) (GDataClass*)get_object(id, binfo)
- #define get_generic(id,binfo) (GenericData*)get_object(id, binfo)
-
- #define put_extent_data(id,binfo,obj) put_object(id, binfo, obj)
- #define put_class(id,binfo,obj) put_object(id, binfo, obj)
- #define put_generic(id,binfo,obj) put_object(id, binfo, obj)
-
- #define remove_extent_data(id,binfo) remove_object(id, binfo)
- #define remove_class(id,binfo) remove_object(id, binfo)
- #define remove_generic(id,binfo) remove_object(id, binfo)
-
- #define DEBUGGER_PSHEET_NAME "DEBUGGER_P_SHEET"
-
- /* special graphics attribute meaning "use what anyone else's attributes" */
- #define GA_NO_CHANGE 0
- /* this number should be bigger than any of the "real" GA's */
- #define GA_MAX 0x1000
-
- /**************************** Utilities *****************************/
-
- static int
- emacs_CWriteRequestBuffer (Connection* conn)
- {
- int result;
- /* don't kill emacs with SIGPIPE */
- SIGTYPE (*old_sigpipe)() =
- (SIGTYPE (*) ()) signal (SIGPIPE, SIG_IGN);
-
- result = CWriteRequestBuffer (conn); /* the real one; macroized later */
- signal (SIGPIPE, old_sigpipe);
- return result;
- }
-
- #define CWriteRequestBuffer emacs_CWriteRequestBuffer
-
-
- static Energize_Extent_Data *
- extent_to_data (Lisp_Object extent_obj)
- {
- Energize_Extent_Data *ext = 0;
-
- if (!EXTENTP (extent_obj))
- return 0;
- else
- ext = energize_extent_data (XEXTENT (extent_obj));
-
- if (ext)
- {
- if (EQ (ext->extent, extent_obj))
- return ext;
- else
- abort ();
- }
- else
- return 0;
- }
-
-
- static Lisp_Object
- data_to_extent (Energize_Extent_Data *ext)
- {
- Lisp_Object extent = ext->extent;
- assert (EXTENTP (extent));
- return extent;
- }
-
- /* duplicate a string */
- static char*
- copy_string (char *s)
- {
- if (!s)
- return 0;
- else
- {
- int len = strlen (s);
- char *res = (char *) xmalloc (len + 1);
- return strcpy (res, s);
- }
- }
-
- /* Get objects from the hashtables */
- static CONST void *
- get_object_internal (EId id, c_hashtable table)
- {
- void *res;
- CONST void *found = gethash ((void*)id, table, &res);
-
- if (found) CHECK_OBJECT (res, 0);
-
- return found ? res : 0;
- }
-
- static CONST void *
- get_object (EId id, BufferInfo *binfo)
- {
- return get_object_internal (id, binfo->id_to_object);
- }
-
- static void
- put_object_internal (EId id, c_hashtable table, void *object)
- {
- if (!PUT_ABLE_OBJECT (object))
- error ("Can't put 0x%x in table", object);
- CHECK_OBJECT (object, 0);
- puthash ((void*)id, object, table);
- }
-
- static void
- put_object (EId id, BufferInfo *binfo, void *object)
- {
- put_object_internal (id, binfo->id_to_object, object);
- return;
- }
-
- static void
- remove_object_internal (EId id, c_hashtable table)
- {
- void *res;
-
- if (gethash ((void*)id, table, &res))
- {
- if (OBJECT_FREE (res))
- error ("Free'd object 0x%x still in table!", res);
- remhash ((void*)id, table);
- }
- else if (id)
- /* #### If this happens for Energize_Extent_Data as a result of extent
- finalization, this aborts (because gc_in_progress). These errors are
- awfully bad, so probably they should just be abort()s anyway... */
- error ("EId %d not in table!", id);
- }
-
- static void
- remove_object (EId id, BufferInfo *binfo)
- {
- remove_object_internal (id, binfo->id_to_object);
- return;
- }
-
- /* maphash_function called by free_buffer_info */
- static void
- free_object (void *key, void *contents, void *arg)
- {
- BufferInfo *binfo = arg;
-
- if (contents)
- {
- switch (OBJECT_SEAL (contents))
- {
- case BUF_INFO_SEAL:
- break;
- case EXTENT_SEAL:
- free_Energize_Extent_Data ((Energize_Extent_Data *) contents,
- binfo, OFT_MAPHASH);
- break;
- case GDATA_CLASS_SEAL:
- free_GDataclass ((GDataClass *) contents, binfo);
- break;
- case GDATA_SEAL:
- free_GenericData ((GenericData *) contents, binfo);
- break;
- default:
- error ("Bad argument 0x%x to free_object()", contents);
- return;
- }
- }
- }
-
- static GDataClass *
- alloc_GDataclass (EId id, BufferInfo *binfo)
- {
- GDataClass *cl = xnew (GDataClass);
- memset (cl, 0, sizeof (GDataClass));
- cl->seal = GDATA_CLASS_SEAL;
- cl->id = id;
- put_class (cl->id, binfo, cl);
- return cl;
- }
-
- static void
- free_GDataclass (GDataClass *cl, BufferInfo *binfo)
- {
- if (cl)
- {
- remove_class (cl->id, binfo);
- SET_OBJECT_FREE (cl);
- }
- return;
- }
-
-
- static GenericData *
- alloc_GenericData (EId id, GDataClass *cl, BufferInfo *binfo)
- {
- GenericData *gen = xnew (GenericData);
- gen->seal = GDATA_SEAL;
- gen->id = id;
- gen->cl = cl;
- /* gen->image = 0;*/
- gen->flags = 0;
- gen->modified_state = 0;
- put_generic (gen->id, binfo, gen);
- return gen;
- }
-
- static void
- free_GenericData (GenericData *gen, BufferInfo *binfo)
- {
- if (gen)
- {
- remove_generic (gen->id, binfo);
- gen->cl = 0;
- SET_OBJECT_FREE (gen);
- }
- return;
- }
-
- /* Called to flush the extent from the hash table when Energize tells us to
- lose the extent. This is NOT called from the extent GC finalization method,
- because there would be a period before the next GC when we still had an
- Energize ID that the server thought was dead, and could concievably reuse.
-
- Since we protect extents from GC until Energize says they're done, if an
- extent still has Energize data by the time it gets collected, something is
- fucked.
- */
- static void
- free_Energize_Extent_Data (Energize_Extent_Data *ext, BufferInfo *binfo,
- enum Energize_Object_Free_Type free_type)
- {
- if (ext)
- {
- Lisp_Object extent_obj = data_to_extent (ext);
-
- /* Remove the extent, remove the extent's pointer to the data,
- and the data's pointer to the extent. */
- Fdetach_extent (extent_obj);
- set_energize_extent_data (XEXTENT (extent_obj), 0);
- ext->extent = Qnil; /* at this point, refs will abort */
-
- /* Remove the data from the hash table, and mark it as dead. */
- remove_extent_data (ext->id, binfo);
- ext->id = 0;
-
- /* don't free this "sub-guy" via maphash, as it will get taken care
- of during the course of the maphash without our doing anything */
- if (free_type != OFT_MAPHASH)
- {
- if (ext->extentType == CEGeneric)
- free_GenericData (ext->u.generic.gData, binfo);
- }
-
- SET_OBJECT_FREE (ext);
- }
- return;
- }
-
- void
- energize_extent_finalization (EXTENT extent)
- {
- /* In the new world, extents are protected from GC until Energize is
- done with them, so if we GC an extent that still has Energize
- data, that means the extents weren't properly protected. */
- /*
- Except that in the even newer world, we can't do this check because the
- Energize_Extent_Data is pointed to by a cons that may have been collected
- already, so CDRing down the extent->plist can crash. Oh well.
-
- Energize_Extent_Data *ext = energize_extent_data (extent);
- if (ext) abort ();
- */
- }
-
- static BufferInfo *
- alloc_BufferInfo (EId id, Lisp_Object name, Lisp_Object filename,
- char *class_str, Editor *editor, Window win, int nobjects)
- {
- BufferInfo *binfo = xnew (BufferInfo);
- Widget nw = 0;
- Lisp_Object buffer = Qnil;
-
- if (win)
- {
- char win_as_string [16];
- nw = XtWindowToWidget (get_x_display (Qnil), win);
- if (nw)
- nw = XtParent (nw);
-
- if (nw)
- sprintf (win_as_string, "w%x", nw);
- else
- sprintf (win_as_string, "0x%x", win);
- binfo->frame =
- Fx_create_frame (Qnil, Qnil, build_string (win_as_string));
- }
- else
- binfo->frame = Qnil;
-
- /* try to re-use a buffer with the same file name if one already exists.
- * If a buffer already exists but is modified we should do a dialog and
- * ask the user what to do. For now I'll just use a new buffer in that case.
- * ParseBuffer will erase the buffer.
- */
- if (!NILP (filename))
- {
- int offct = find_file_compare_truenames;
- find_file_compare_truenames = 1;
- buffer = Fget_file_buffer (filename);
- find_file_compare_truenames = offct;
-
- if (!NILP (buffer) && !NILP (Fbuffer_modified_p (buffer)))
- buffer = Qnil;
- }
-
- if (NILP (buffer))
- buffer = Fget_buffer_create (Fgenerate_new_buffer_name (name, Qnil));
-
- binfo->seal = BUF_INFO_SEAL;
- binfo->id = id;
- binfo->flags = 0;
- binfo->editor = editor;
- binfo->id_to_object = make_hashtable (nobjects);
- binfo->emacs_buffer = buffer;
- binfo->modified_state = 0;
- binfo->editable = 0;
- binfo->output_mark = Qnil;
- binfo->buffer_type = kernel_buffer_type_to_elisp_type (class_str);
- binfo->p_sheet_ids = 0;
- binfo->n_p_sheets = 0;
- binfo->note_ids = 0;
- binfo->n_notes = 0;
- #ifdef I18N4
- binfo->wcmap.valid = 0;
- binfo->wcmap.modiff_stamp = -1;
- binfo->wcmap.map = NULL;
- #endif
- put_buffer_info (id, binfo->emacs_buffer, binfo, editor);
-
- Venergize_buffers_list = Fcons (buffer, Venergize_buffers_list);
-
- #if 0
- * if (nw){
- * Lisp_Object window = Fframe_selected_window (binfo->frame);
- * Fset_window_buffer (window, binfo->emacs_buffer);
- * set_text_widget ((NoteWidget)nw,
- * FRAME_X_SHELL_WIDGET (XFRAME (binfo->frame)));
- * }
- #endif
-
- return binfo;
- }
-
- /* free a buffer_info */
- static void
- free_buffer_info (BufferInfo *binfo)
- {
- maphash (free_object, binfo->id_to_object, (void *)binfo);
- free_hashtable (binfo->id_to_object);
- if (energize_connection && energize_connection->binfo_hash)
- {
- if (binfo->id)
- remhash ((void *)binfo->id, energize_connection->binfo_hash);
- if (!NILP (binfo->emacs_buffer))
- {
- remhash (LISP_TO_VOID (binfo->emacs_buffer),
- energize_connection->binfo_hash);
- }
- }
- binfo->id = 0;
- binfo->emacs_buffer = Qnil;
- #ifdef I18N4
- if (binfo->wcmap.valid) {
- binfo->wcmap.valid= 0;
- xfree(binfo->wcmap.map);
- }
- #endif
- SET_OBJECT_FREE (binfo);
- }
-
- /* hash for BufferInfo structures */
- static BufferInfo*
- get_buffer_info_for_emacs_buffer (Lisp_Object emacs_buf, Editor *editor)
- {
- BufferInfo *res;
- if (!editor || !editor->binfo_hash)
- return 0;
- else
- {
- void *vbuf;
- /* #### Probably should use a Lisp hash table for this; what if the last
- pointer to the buffer was in the editor struct? */
- return (gethash (LISP_TO_VOID (emacs_buf),
- editor->binfo_hash,
- (void *) &res)
- ? res : 0);
- }
- }
-
-
-
- /* Called by mark_buffer. It is possible for the last remaining pointer to
- an extent object to be in an Energize_Extent_Data structure that is pointed
- at by the binfo->id_to_object table. Since Energize may still reference
- this object by its id (in fact, I think it may even "ressurect" a detached
- extent) we must prevent the extent from being garbage collected. Aside
- from the obvious lossage (that the extent itself would be trashed) this
- would also cause us to free the Energize_Extent_Data which the server still
- believes we have. The buffers all get marked because they're on the
- `Venergize_buffers_list'.
-
- So, an Energize extent or buffer only ever gets collected when the server
- has claimed that it is done with it (or when the connection is closed).
-
- Of course, by keeping pointers to lisp objects in C structs under non-lisp
- hash tables, we again build in the assumption that GC never relocates.
- */
-
- /* FUCK!! It's not standard-conforming to cast pointers to functions
- to or from void*. Give me a fucking break! */
- struct markobj_kludge_fmh
- {
- void (*markobj) (Lisp_Object);
- };
-
- static void
- mark_energize_buffer_data_extent_mapper (void *key, void *val, void *arg)
- {
- if (OBJECT_SEAL (val) == EXTENT_SEAL)
- {
- struct markobj_kludge_fmh *fmh = arg;
- struct Energize_Extent_Data *ext = (Energize_Extent_Data *) val;
- /* Lisp_Object extent = data_to_extent (ext); (will abort if marked) */
- Lisp_Object extent = ext->extent;
- assert (gc_record_type_p (extent, lrecord_extent));
- ((*fmh->markobj) (extent));
- }
- }
-
- void
- mark_energize_buffer_data (struct buffer *b,
- void (*markobj) (Lisp_Object))
- {
- struct markobj_kludge_fmh fmh;
- Lisp_Object buffer;
- BufferInfo *binfo;
- if (!energize_connection || !energize_connection->binfo_hash)
- return;
- XSETBUFFER (buffer, b);
- binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection);
- if (! binfo)
- return;
- fmh.markobj = markobj;
- maphash (mark_energize_buffer_data_extent_mapper, binfo->id_to_object, &fmh);
- }
-
-
-
- struct buffer_and_sheet_ids
- {
- EId buffer_id;
- EId sheet_id;
- };
-
- static void
- find_sheet_id (void* key, void* contents, void* arg)
- {
- BufferInfo* binfo = (BufferInfo*)contents;
- EId buffer_id = (EId)key;
- struct buffer_and_sheet_ids* result = (struct buffer_and_sheet_ids*)arg;
- int i;
-
- if (!result->buffer_id)
- for (i = 0; i < binfo->n_p_sheets; i++)
- if (binfo->p_sheet_ids [i] == result->sheet_id)
- {
- result->buffer_id = buffer_id;
- return;
- }
- }
-
- static EId
- buffer_id_of_sheet (EId id)
- {
- Editor *editor = energize_connection;
- struct buffer_and_sheet_ids basi;
- if (!energize_connection)
- return 0;
-
- basi.buffer_id = 0;
- basi.sheet_id = id;
- maphash (find_sheet_id, editor->binfo_hash, (void*)&basi);
- return basi.buffer_id;
- }
-
- static long
- get_energize_buffer_id (Lisp_Object emacs_buf)
- {
- Editor *editor = energize_connection;
- BufferInfo *res;
-
- if (!editor || !editor->binfo_hash)
- return -1;
- else if (!gethash (LISP_TO_VOID (emacs_buf), editor->binfo_hash, (void *)&res))
- return -1;
- else
- return (long) res->id;
- }
-
- static char *
- kernel_buffer_type_to_elisp_type (char *kernel_type)
- {
- struct buffer_type_struct *bts =
- kernel_buffer_types_to_elisp_buffer_types_vector;
- char *elisp_type = 0;
-
- if (!kernel_type)
- return UNINITIALIZED_BUFFER_TYPE;
-
- while (bts->kernel_name)
- {
- if (!strcmp (bts->kernel_name, kernel_type))
- {
- elisp_type = bts->elisp_name;
- break;
- }
- bts++;
- }
-
- if (!elisp_type)
- return kernel_type;
- else
- return elisp_type;
- }
-
- static Lisp_Object
- get_buffer_type_for_emacs_buffer (Lisp_Object emacs_buf, Editor *editor)
- {
- BufferInfo *binfo;
- if (!(binfo = get_buffer_info_for_emacs_buffer (emacs_buf, editor)))
- return Qnil;
- else
- {
- if (!binfo->buffer_type) binfo->buffer_type =
- UNINITIALIZED_BUFFER_TYPE;
-
- return intern (binfo->buffer_type);
- }
- }
-
- static Lisp_Object
- set_buffer_type_for_emacs_buffer (Lisp_Object emacs_buf, Editor *editor,
- Lisp_Object type)
- {
- BufferInfo *binfo;
- if (!(binfo = get_buffer_info_for_emacs_buffer (emacs_buf, editor)))
- return Qnil;
- else
- {
- char *type_string;
-
- if (NILP (type)) return Qnil;
-
- if (SYMBOLP (type))
- XSETSTRING (type, XSYMBOL (type)->name);
-
- if (STRINGP (type))
- type_string = (char *)string_data (XSTRING (type));
-
- type_string = copy_string (type_string);
-
- if (!type_string) return Qnil;
-
- binfo->buffer_type = type_string;
-
- return intern (binfo->buffer_type);
- }
- }
-
- static BufferInfo*
- get_buffer_info_for_id (EId id, Editor *editor)
- {
- BufferInfo *res;
- return (gethash ((void *)id, editor->binfo_hash, (void *)&res))?res:0;
- }
-
- static void
- put_buffer_info (EId id, Lisp_Object emacs_buf, BufferInfo *binfo,
- Editor *editor)
- {
- puthash ((void *)id, binfo, editor->binfo_hash);
- puthash (LISP_TO_VOID (emacs_buf), binfo, editor->binfo_hash);
- }
-
- static void
- remove_buffer_info (EId id, Lisp_Object emacs_buf, Editor *editor)
- {
- void *vbuf;
- remhash ((void *)id, editor->binfo_hash);
- remhash (LISP_TO_VOID (emacs_buf), editor->binfo_hash);
- }
-
-
- /* Conversion between Energize and Emacs buffer positions */
-
- #if defined(I18N4)
-
- /* An emacs position is an index into the buffer... In I18N, foreign
- characters take up the same amount of space as ASCII characters. Emacs
- is using wide characters. The first position is 1.
-
- An energize position is a straight byte offset into the file when it's
- saved onto disk. Foreign characters take up more than one byte. The
- first position is 0. */
-
- #define WCMAP_SETSIZE(wcmap,n) { \
- (wcmap).mapsize = (n); \
- (wcmap).map = (WCharMapRec *) xrealloc((wcmap).map, \
- (n) * sizeof(WCharMapRec)); \
- }
- #define WCMAP_ENLARGE(wcmap) WCMAP_SETSIZE(wcmap, 2*(wcmap.mapsize))
-
- #ifndef MB_LEN_MAX
- #define MB_LEN_MAX 10 /* arbitrarily large enough */
- #endif
-
- static char wcsize_buf[MB_LEN_MAX];
- #define WCSIZE(wc) (isascii(wc) ? 1 : wctomb(wcsize_buf,wc))
-
- #define SANITY_CHECK_NOT
- #ifdef SANITY_CHECK
- static int sanity=0;
- #endif
-
- static void
- sync_buffer_widechar_map (BufferInfo *binfo)
- {
- /* #### - check this: */
- assert (XBUFFER (binfo->emacs_buffer) == current_buffer);
-
- if (!binfo->wcmap.valid)
- {
- binfo->wcmap.valid= 1;
- binfo->wcmap.modiff_stamp= -1;
- binfo->wcmap.map= NULL;
- WCMAP_SETSIZE (binfo->wcmap, 1);
- }
-
- if (binfo->wcmap.modiff_stamp == BUF_MODIFF (current_buffer))
- {
- return;
- }
- else
- {
- int nbytes, maxpos,
- pos = 0, /* start at zero instead of 1 */
- adjustment = 0,
- mapindex= 0;
- wchar_t *buf, t;
-
- #ifdef SANITY_CHECK
- stderr_out ("rebuilding widechar map for %s\n", string_data (XSTRING (current_buffer->name)));
- #endif
-
- /* #### this is not gonna compile. move_gap() is now a private function
- inside of insdel.c and it should stay that way. */
- if (BUF_BEGV (current_buffer) < GPT && BUF_ZV (current_buffer) > GPT)
- move_gap (current_buffer, BUF_BEGV (current_buffer));
- binfo->wcmap.modiff_stamp = BUF_MODIFF (current_buffer);
-
- buf = BUF_BEG_ADDR (current_buffer);
- maxpos= (BUF_Z (current_buffer) - 1);
- wctomb (NULL, 0); /* reset shift state of wctomb() */
- binfo->wcmap.map[mapindex].pos= pos;
- binfo->wcmap.map[mapindex].eucsize=
- ((pos<maxpos) ? (nbytes= WCSIZE(buf[pos])) : 1);
- do {
- while ((pos < maxpos) && (nbytes == WCSIZE(t = buf[pos])))
- ++pos;
- binfo->wcmap.map[mapindex++].endpos= pos;
- if (mapindex == binfo->wcmap.mapsize)
- WCMAP_ENLARGE(binfo->wcmap);
- if (pos < maxpos)
- {
- binfo->wcmap.map[mapindex].pos= pos;
- binfo->wcmap.map[mapindex].eucsize= nbytes= WCSIZE(t);
- }
- } while (pos < maxpos);
- WCMAP_SETSIZE(binfo->wcmap, mapindex);
- }
- }
-
- static EnergizePos
- EnergizePosForBufpos (Bufpos char_pos, BufferInfo *binfo)
- {
- int mapindex;
- WCharMapRec map;
- EnergizePos byte_pos;
-
- sync_buffer_widechar_map (binfo);
-
- --char_pos; /* preadjust emacs position */
-
- mapindex=0, byte_pos=0;
- while ((mapindex < binfo->wcmap.mapsize) &&
- (char_pos > (map= binfo->wcmap.map[mapindex++]).pos)) {
- if (char_pos > map.endpos) {
- byte_pos += ((map.endpos - map.pos) * map.eucsize);
- } else {
- byte_pos += ((char_pos - map.pos) * map.eucsize);
- }
- }
- /* there should be a sanity check here */
- #ifdef CHECK_SANITY
- if (!sanity) {
- Bufpos check_pos;
- sanity=1;
- check_pos= BufposForEnergizePos(byte_pos, binfo);
- sanity=0;
-
- if (check_pos != char_pos) {
- stderr_out ("ezpos(%d) = %d, Bufpos(%d) = %d\n",
- char_pos, byte_pos, byte_pos, check_pos);
- }
- }
- #endif
- return byte_pos;
- }
-
- static Bufpos
- BufposForEnergizePos (EnergizePos ez_pos, BufferInfo *binfo)
- {
- int mapindex, x;
- WCharMapRec map;
- Bufpos char_pos;
- EnergizePos byte_pos;
-
- sync_buffer_widechar_map(binfo);
-
- mapindex=0, byte_pos=0;
- while ((mapindex < binfo->wcmap.mapsize) &&
- (byte_pos <= ez_pos)) {
- map= binfo->wcmap.map[mapindex++];
- x= (map.eucsize*(map.endpos-map.pos));
- if (ez_pos > (byte_pos + x)) {
- byte_pos += x;
- char_pos = map.endpos;
- } else {
- char_pos = (map.pos + ((ez_pos - byte_pos)/map.eucsize));
- break;
- }
- }
- char_pos= (char_pos >= (1 << VALBITS)) ? BUF_Z (current_buffer) :
- (char_pos + 1);
- #ifdef CHECK_SANITY
- if (!sanity) {
- EnergizePos check_pos;
- sanity=1;
- check_pos= EnergizePosForBufpos(char_pos);
- sanity=0;
-
- if (check_pos != ez_pos) {
- stderr_out ("Bufpos(%d) = %d, EnergizePosForBufpos(%d) = %d\n",
- ez_pos, char_pos, char_pos, check_pos);
- }
- }
- #endif
- return (char_pos);
- }
-
- #else /* !I18N4 */
-
- static Bufpos
- BufposForEnergizePos (EnergizePos energizePos, BufferInfo *binfo)
- {
- return ((energizePos >= (1 << VALBITS)) ? BUF_Z (current_buffer) :
- (energizePos + 1));
- }
-
- static EnergizePos
- EnergizePosForBufpos (Bufpos emacs_pos, BufferInfo *binfo)
- {
- return (emacs_pos - 1);
- }
-
- #endif /* !I18N4 */
-
- /* extent data */
-
- Energize_Extent_Data *
- energize_extent_data (EXTENT extent)
- {
- Lisp_Object data = extent_getf (extent, Qenergize);
- if (NILP (data))
- return 0;
- return ((Energize_Extent_Data *) get_opaque_ptr (data));
- }
-
- static void
- set_energize_extent_data (EXTENT e, void *data)
- {
- extent_putf (e, Qenergize, make_opaque_ptr (data));
- }
-
-
- DEFUN ("energize-update-menubar", Fenergize_update_menubar,
- Senergize_update_menubar, 0, 1, 0,
- "obsolete")
- (frame)
- Lisp_Object frame;
- {
- return Qnil;
- }
-
-
- DEFUN ("energize-extent-menu-p", Fenergize_extent_menu_p,
- Senergize_extent_menu_p, 1, 1, 0,
- "Whether the extent has a set of commands defined by Energize.")
- (extent_obj)
- Lisp_Object extent_obj;
- {
- CHECK_EXTENT (extent_obj, 0);
-
- if (NILP (Fconnected_to_energize_p ()))
- return Qnil;
- else
- {
- Energize_Extent_Data *ext = extent_to_data (extent_obj);
- return (ext && ext->extentType == CEGeneric) ? Qt : Qnil;
- }
- }
-
-
- /* Do what is needed so that the delayed requests will be notified by
- ** the event loop */
-
- extern void mark_process_as_being_ready (struct Lisp_Process* process);
-
- static void
- notify_delayed_requests (void)
- {
- if (energize_connection
- && !NILP (energize_connection->proc)
- && energize_connection->conn
- && CRequestDelayedP (energize_connection->conn))
- this function no longer exists.
- (Replaced by mark_what_as_being_ready, with different arguments.)
- Rewrite this.
- mark_process_as_being_ready (XPROCESS (energize_connection->proc));
- }
-
-
- /******************* IMAGE storage maintenance *******************/
-
- extern GLYPH image_instance_to_glyph (Lisp_Object);
-
- static c_hashtable image_cache;
-
- extern char *strdup ();
- extern Lisp_Object Fbuffer_file_name (Lisp_Object);
-
-
- extern Lisp_Object Fmake_face (Lisp_Object name);
- extern Lisp_Object Fface_foreground (Lisp_Object face, Lisp_Object frame);
- extern Lisp_Object Fface_background (Lisp_Object face, Lisp_Object frame);
-
- /* Don't let any of these get GCed, since we hold their GLYPH ids in
- a non-lisp hash table (image_cache) . */
- static Lisp_Object Vall_energize_pixmaps;
-
- /* Parses an image from the image language */
- static GLYPH
- read_energize_image_data (Connection *conn, BufferInfo *binfo)
- {
- ReqLen l;
- char *s = CGetVstring (conn, &l);
- char pix_name [255];
- char buf [255];
- int attr_number, pix_len;
- char *file;
- GLYPH result = 0;
- /* It is bad news to pass the address of a short to gethash. */
- int hashed = 0;
-
- if (s[0] != 'f')
- return 0;
-
- if (gethash ((void *) s, image_cache, (void *) &hashed))
- /* If we have already parsed this image spec (string=) then just return
- the old glyph, instead of calling the lisp code, x_get_pixmap, and
- XtGetSubResources again. The result may be 0 if there is no pixmap
- file name in the resource database.
- */
- return (GLYPH) hashed;
-
- if (3 != sscanf (s, "f %d p %d %s", &attr_number, &pix_len, pix_name))
- {
- sprintf (buf, "unparsable image: \"%s\"", s);
- error (buf);
- }
-
- assert (pix_len == strlen (pix_name));
-
- /* Read the pixmap file name for this image from the resource db */
- {
- XtResource resource [1];
- resource[0].resource_name = pix_name;
- resource[0].resource_class = XtCBitmap;
- resource[0].resource_type = XtRString;
- resource[0].resource_size = sizeof (char *);
- resource[0].resource_offset = 0;
- resource[0].default_type = XtRImmediate;
- resource[0].default_addr = 0;
- file = 0;
- XtGetSubresources (FRAME_X_SHELL_WIDGET (XFRAME (Fselected_frame (Qnil))),
- (XtPointer) &file, "image", "Image", resource, 1, NULL,
- 0);
- }
-
- if (! file)
- result = 0;
- else
- {
- Lisp_Object lfile = Qnil;
- Lisp_Object p = Qnil;
- struct gcpro gcpro1, gcpro2;
- sprintf (buf, "attribute%d", attr_number);
- GCPRO2 (lfile, p);
- lfile = build_string (file);
- p = Fmake_image_instance (lfile, Qnil); /* may gc */
- result = image_instance_to_glyph (p);
- Vall_energize_pixmaps = Fcons (Fcons (make_number (result), p),
- Vall_energize_pixmaps);
- if (!EQ (p, glyph_to_image_instance (result)))
- abort ();
- UNGCPRO;
-
- if (XIMAGE_INSTANCE (p)->depth == 0)
- /* if depth is >0 then this is an XPM, and its colors are not
- controlled by the fg/bg of a face. So don't bother making a
- face for it. */
- {
- Lisp_Object face, fg, bg;
- struct face *c_face;
- /* #### review this */
- face = Fmake_face (intern (buf));
- fg = FACE_FOREGROUND (face, Qnil);
- bg = FACE_BACKGROUND (face, Qnil);
- Fcolorize_image_instance (p, fg, bg);
- }
- }
-
- /* CGetVstring returns a pointer into the connection buffer; we need to
- copy it to use it as a hash key. */
- s = strdup (s);
-
- hashed = result;
- puthash ((void *) s, (void *) hashed, image_cache);
- return result;
- }
-
-
- /* Parses Classes from the connection buffer. Defines them for
- * the buffer given as argument */
- static void
- read_energize_class_data (Connection *conn, unsigned int number,
- BufferInfo *binfo, unsigned int modify_ok)
- {
- CClass *ptr; /* pointer to class data in buffer */
- GDataClass *cl; /* unmodified class data */
- GLYPH g;
- int i;
-
- for (i = 0; i < number; i++)
- {
- ptr = CGet (conn, CClass);
- g = read_energize_image_data (conn, binfo);
- cl = get_class (ptr->classId, binfo);
-
- if (!cl)
- cl = alloc_GDataclass (ptr->classId, binfo);
- else if (!modify_ok)
- message("Attempt to create class with existing Id %8x", ptr->classId);
-
- if (ignore_kernel) continue;
-
- /* if it did exist, we just clobber it */
- if (cl->flags != ptr->flags)
- {
- cl->flags = ptr->flags;
- BUF_FACECHANGE (XBUFFER (binfo->emacs_buffer))++;
- }
- if (cl->glyph != g)
- {
- cl->glyph = g;
- BUF_FACECHANGE (XBUFFER (binfo->emacs_buffer))++;
- }
- }
- }
-
- /* Parse GenericData form the connection buffer. Defines them for the buffer
- * given as argument */
- static void
- read_energize_generic_data (Connection *conn, unsigned int number,
- BufferInfo *binfo, unsigned int modify_ok)
- {
- CGeneric *ptr;
- GenericData *gen;
- GDataClass *cl;
- GLYPH g;
- int i;
-
- for (i = 0; i < number; i++)
- {
- ptr = CGet (conn, CGeneric);
- g = read_energize_image_data (conn, binfo);
- gen = get_generic (ptr->genericId, binfo);
- cl = get_class (ptr->classId, binfo);
-
- if (!gen)
- {
- /* create generic if it didn't already exist */
-
- if (!cl)
- {
- message ("Attempt to create generic %8x with undefined class %8x",
- ptr->genericId, ptr->classId);
- continue;
- }
-
- gen = alloc_GenericData (ptr->genericId, cl, binfo);
- gen->glyph = g;
- if (ptr->flags != 0xff) gen->flags = ptr->flags;
- gen->attribute = ptr->attribute;
- }
- else if (!modify_ok)
- message("Attempt to create generic with existing id %8x",
- ptr->genericId);
- else{
- /* modify the generic */
- int modified = 0;
- if (cl != gen->cl)
- {
- modified = 1;
- gen->cl = cl;
- }
- if (gen->glyph != g)
- {
- modified = 1;
- gen->glyph = g;
- }
- if (ptr->flags != 0xff)
- {
- modified = 1;
- gen->flags = ptr->flags;
- }
- if (gen->attribute != ptr->attribute)
- {
- modified = 1;
- gen->attribute = ptr->attribute;
- }
- if (modified)
- BUF_FACECHANGE (XBUFFER (binfo->emacs_buffer))++;
- }
- }
- }
-
-
- static void
- insert_one_extent (CExtent* ptr, BufferInfo* binfo, int modify_ok)
- {
- Energize_Extent_Data *ext;
- GenericData *gen;
- Bufpos extent_start;
- Bufpos extent_end;
- int set_endpoints_p = 1;
- int created_ext_data = 0;
- Lisp_Object buffer = binfo->emacs_buffer;
-
- ext = get_extent_data (ptr->extentId, binfo);
-
- if (!ext)
- {
- ext = (Energize_Extent_Data *) xmalloc (sizeof (Energize_Extent_Data));
- created_ext_data = 1;
- ext->seal = EXTENT_SEAL;
- ext->id = ptr->extentId;
- ext->extentType = -1;
- ext->extent = Qnil; /* not a normal value: set before we return */
- ext->start_pixmap = 0;
- ext->end_pixmap = 0;
- ext->warn_modify = 0;
- put_extent_data (ext->id, binfo, ext);
- }
- else if (!modify_ok)
- message ("Creating extent with existing id %8x", ptr->extentId);
-
- ext->extentType = ptr->extentType;
-
- switch (ptr->extentType)
- {
- case CEAttribute:
- ext->u.attr.attrValue = ptr->data;
- break;
-
- case CEAbbreviation:
- ext->u.abbrev.isOpened = ptr->data;
- break;
-
- case CEWriteProtect:
- break;
-
- case CEGeneric:
- gen = get_generic (ptr->data, binfo);
- if (!gen)
- {
- message ("NewExtents: Nonexistent generic data %8x", ptr->data);
- return;
- }
- ext->u.generic.gData = gen;
- break;
-
- default:
- message ("Unknown extent type %d", ptr->extentType);
- break;
- }
-
- /* instruct redisplay to recompute the frame */
- BUF_FACECHANGE (XBUFFER (binfo->emacs_buffer))++;
-
- /* ptr->startPosition == ptr->endPosition == ~0 means to not change
- * the extent endpoints */
- if (ptr->startPosition == ~0 && ptr->endPosition == ~0)
- {
- set_endpoints_p = 0;
- extent_start = ~0;
- extent_end = ~0;
- }
- else
- {
- struct buffer *b = XBUFFER (buffer);
- extent_start = BufposForEnergizePos (ptr->startPosition, binfo);
- extent_end = BufposForEnergizePos (ptr->endPosition, binfo);
-
- /* We have to be careful to create the extents with endpoints
- which are in the buffer.
-
- Under certain obscure conditions involving changes made outside
- of Emacs (bug 19983), the server and the editor can have different
- ideas about where the extents are, so these numbers can be off
- temporarily (during the window between read_energize_extent_data
- and Qenergize_auto_revert_buffer in read_energize_buffer_data
- from ModifyBufferRType).
- */
-
- /* Don't allow 0-length extents, as they tend to disappear. */
- if (extent_start >= extent_end)
- extent_end = extent_start + 1;
-
- /* Don't let them outside the buffer (even if we grew them). */
- if (extent_start >= BUF_Z (b)) extent_start = BUF_Z (b) - 1;
- if (extent_end >= BUF_Z (b)) extent_end = BUF_Z (b) - 1;
- if (extent_start < BUF_BEG (b)) extent_start = BUF_BEG (b);
- if (extent_end < BUF_BEG (b)) extent_end = BUF_BEG (b);
-
- /* If they're 0-length again, then the extent must be at point-max.
- In that case, extent it backward (if possible) instead of forward.
- */
- if (extent_start >= extent_end
- && BUF_BEG (b) != BUF_Z (b))
- extent_start = extent_end - 1;
- }
-
- /* no zero width extent */
- if (set_endpoints_p && extent_start == extent_end)
- extent_end += 1;
-
- /* Now create the extent for the extent-data. There is a 1:1 mapping between
- these, and an extent-data points at an extent (and that extent points
- back) until energize tells us to delete the extent. This is the only
- function in which ext->extent is ever not an extent. */
- if (created_ext_data)
- {
- ext->extent = Fmake_extent (make_number (extent_start),
- make_number (extent_end), buffer);
- set_energize_extent_data (XEXTENT (ext->extent), ext);
- restore_energize_extent_state (XEXTENT (ext->extent));
- }
- else
- {
- if (!EQ (buffer, extent_buffer (XEXTENT (ext->extent))))
- signal_simple_error_2 ("extent not part of buffer", ext->extent,
- buffer);
-
- if (set_endpoints_p)
- Fset_extent_endpoints (ext->extent, make_number (extent_start),
- make_number (extent_end));
- restore_energize_extent_state (XEXTENT (ext->extent));
- }
-
- if (energize_extent_data (XEXTENT (ext->extent)) != ext)
- abort ();
-
- extent_duplicable_p (XEXTENT (ext->extent)) = 1;
- extent_unique_p (XEXTENT (ext->extent)) = 1;
- }
-
-
- /* Parse GenericData from the connection buffer. Defines them for the buffer
- * given as argument. Creates the Emacs extents while parsing.
- * Energize sends the extents ordered by increasing starting position.
- I don't think the following is true any more:
- * Emacs is __much__ faster at inserting them in decreasing starting position
- * also for overlaps to work correctly the outmost extents have to be
- * inserted first. This is what the recursive function is trying to do.
- */
- static void
- read_energize_extent_data (Connection *conn, unsigned int number,
- BufferInfo *binfo, unsigned int modify_ok,
- int extent_offset)
- {
- CExtent* all_extents;
- int i;
-
- /* Gets the extents from the connection */
- all_extents = CGetN (conn, CExtent, number);
-
- /* adjusts the endpoints with the offset */
- for (i = 0; i < number; i++)
- {
- if (all_extents [i].startPosition != ~0)
- all_extents [i].startPosition += extent_offset;
- if (all_extents [i].endPosition != ~0)
- all_extents [i].endPosition += extent_offset;
- }
-
- /* inserts them all */
- for (i = number - 1; i >= 0; i--)
- {
- insert_one_extent (all_extents + i, binfo, modify_ok);
- }
- }
-
- /* Parses a CBuffer in the connection stream. If (delete_from != delete_to)
- all characters in this range must be deleted.
- */
-
- static int
- string_buffer_compare (char *string, int string_len,
- struct buffer *buf, Bufpos bufpos)
- {
- /* !!#### needs to be rewritten for Mule */
- Bufpos first_section_end = BUF_CEILING_OF (buf, bufpos);
-
- /* degenerate case, which we consider to be "true" */
- if (string_len == 0) return 0;
-
- /* string won't fit in the buffer, so comparison fails */
- if (BUF_Z (buf) < (bufpos + string_len)) return -1;
-
- /* bad starting position, so comparison fails */
- if (bufpos < BUF_BEG (buf)) return -1;
-
- {
- char *first_section_chars = (char *) BUF_BYTE_ADDRESS (buf, bufpos);
- int comp = strncmp (string, first_section_chars,
- first_section_end - bufpos);
-
- if (comp) return comp;
- }
-
- if (first_section_end < BUF_ZV (buf))
- /* there is a second section */
- {
- char *second_section_chars =
- (char *) BUF_BYTE_ADDRESS (buf, first_section_end);
- int comp = strncmp (string + (first_section_end - bufpos),
- second_section_chars,
- BUF_ZV (buf) - first_section_end);
-
- if (comp) return comp;
- }
-
- return 0;
- }
-
- /* called by unwind protect, from within ParseBuffer and HandleRemoveExtents */
- static Lisp_Object
- restore_buffer_state (Lisp_Object state_cons)
- {
- BufferInfo *binfo;
- Lisp_Object bufferId_obj = Fcar (state_cons);
- unsigned int bufferId = (unsigned int) get_opaque_ptr (bufferId_obj);
- Lisp_Object buffer_modified_state = Fcar (Fcdr (state_cons));
- Lisp_Object clear_undo_list = Fcdr (Fcdr (state_cons));
-
- if (bufferId != 0)
- {
- if (energize_connection
- && (binfo = get_buffer_info_for_id (bufferId, energize_connection))
- && !NILP (binfo->emacs_buffer))
- {
- /* Always ignore what Energize tells us about the buffer read-only
- state. For files Emacs knows better and for non-file buffers
- Emacs is hacking the read-only state anyway so let it be. */
- XBUFFER (binfo->emacs_buffer)->read_only = buffer_modified_state;
- if (!NILP (clear_undo_list))
- XBUFFER (binfo->emacs_buffer)->undo_list = Qnil;
- }
- }
- else
- /* this is just temporary */
- message ("Bad bufferId cons cell!");
- return Qnil;
- }
-
- /* #### this shit should be using generate-new-buffer */
- static void
- rename_the_buffer (Lisp_Object new_name)
- {
- int count = 0;
- char number [8];
- struct gcpro gcpro1;
-
- Lisp_Object name = new_name;
- GCPRO1 (name);
- while (!NILP (Fget_buffer (name)))
- {
- sprintf (number, "<%d>", ++count);
- name = concat2 (new_name, build_string (number));
- }
- Frename_buffer (name, Qnil);
- UNGCPRO;
- }
-
- static int
- destroy_if_energize_extent (EXTENT e, void* arg)
- {
- struct Energize_Extent_Data *ext = energize_extent_data (e);
- if (ext)
- {
- Lisp_Object extent;
- Lisp_Object buffer;
- BufferInfo *binfo = 0;
- XSETEXTENT (extent, e);
- buffer = extent_buffer (XEXTENT (extent));
- Fdelete_extent (extent);
- if (BUFFERP (buffer))
- binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection);
- if (binfo)
- free_Energize_Extent_Data (ext, binfo, OFT_GC);
- else
- {
- /* #### partly duplicated in free_Energize_Extent_Data() */
- set_energize_extent_data (e, 0);
- ext->extent = Qnil;
- }
- }
- return 0;
- }
-
- static void
- destroy_all_energize_extents (struct buffer *buf)
- {
- map_extents (BUF_BEG (buf), BUF_Z (buf), destroy_if_energize_extent,
- NULL, make_buffer (buf), 0,
- ME_END_CLOSED | ME_MIGHT_MODIFY_EXTENTS);
- }
-
- static Lisp_Object
- restore_inside_parse_buffer (Lisp_Object val)
- {
- inside_parse_buffer = XINT (val);
- return (val);
- }
-
- static void
- hack_window_point (Lisp_Object window,
- Lisp_Object old_point,
- Lisp_Object old_start,
- int keep_start_p,
- BufferInfo *binfo)
- /* If we've reverted a buffer, sometimes we want to make sure that
- the window-point doesn't move. */
- {
- if (NILP (window))
- return;
-
- Fset_marker (XWINDOW (window)->pointm, old_point, binfo->emacs_buffer);
- if (NILP (binfo->output_mark) && keep_start_p)
- {
- Fset_marker (XWINDOW (window)->start, old_start, binfo->emacs_buffer);
- XWINDOW (window)->force_start = 1;
- }
- }
-
- static void
- read_energize_buffer_data (Connection *conn, CBuffer *cbu, Editor *editor,
- EnergizePos delete_from, EnergizePos delete_to,
- Window win, int relative_p)
- {
- char *name;
- ReqLen name_len;
- char *pathname_str;
- ReqLen pathname_len;
- char *buffer_class_str;
- ReqLen buffer_class_len;
- Lisp_Object pathname = Qnil;
- Lisp_Object pathname_directory = Qnil;
- Lisp_Object buffer_name = Qnil;
- Lisp_Object filename = Qnil;
- #if 1
- Lisp_Object display_window = Qnil;
- #endif
- BufferInfo *binfo;
- int modifying_p = 0;
- Bufpos previous_point;
- Bufpos from;
- Bufpos to;
- #if 1
- Bufpos display_start = 1;
- #endif
- char *text;
- ReqLen text_len;
- int get_chars_from_file = 0;
- Lisp_Object modified_buffer_flag;
- int speccount = specpdl_depth ();
- int extent_offset;
- Lisp_Object restore_buffer_state_cons;
- int should_keep_window_start = 1;
- int no_text_deleted = 0;
-
- struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
-
- /* For some reason calling the GC before parsing the buffer data
- makes a better usage of memory and emacs leaks less when
- creating/deleting LE browser buffers.
- However you don't want to call GC all the tiem so we only do it if the request
- will create more than a given number of extents. */
- if (cbu->nExtent > energize_extent_gc_threshold)
- garbage_collect_1 ();
-
- record_unwind_protect (save_restriction_restore, save_restriction_save ());
-
- Fwiden (Fcurrent_buffer ());
-
- GCPRO4 (buffer_name, pathname, pathname_directory, filename);
-
- name = CGetVstring (conn, &name_len);
-
- /* read the pathname and buffer-class -- Editor Protocol > 0 */
- pathname_str = CGetVstring (conn, &pathname_len);
- buffer_class_str = CGetVstring (conn, &buffer_class_len);
-
- if (name_len)
- buffer_name = build_string (name);
- if (pathname_len)
- pathname = build_string (pathname_str);
-
- /* set up pathname_directory */
- if (!NILP (pathname))
- {
- if (NILP (Ffile_directory_p (pathname)))
- pathname_directory = Ffile_name_directory (pathname);
- else
- pathname_directory = pathname;
- }
-
- /* make sure that pathname_directory ends with a '/', if it exists */
- if (!NILP (pathname_directory))
- {
- Bufbyte *str = string_data (XSTRING (pathname_directory));
- Bytecount size = string_length (XSTRING (pathname_directory));
- if (str[size - 1] != '/')
- {
- Lisp_Object tmp = make_string (str, size + 1);
- set_string_byte (XSTRING (tmp), size, '/');
- pathname_directory = tmp;
- }
- }
-
-
- /* get or create the BufferInfo */
- if (binfo = get_buffer_info_for_id (cbu->bufferId, editor))
- modifying_p = 1;
- else
- {
- if (NILP (buffer_name))
- {
- char *dummy = "*Unnamed " IDENTITY_CRISIS " Buffer*";
- buffer_name = build_string (dummy);
- }
- /* create new buffer */
- binfo = alloc_BufferInfo (cbu->bufferId, buffer_name, pathname,
- buffer_class_str, editor, win,
- cbu->nExtent + cbu->nClass + cbu->nGeneric);
- XBUFFER (binfo->emacs_buffer)->read_only =
- cbu->flags == CBReadOnly ? Qt : Qnil;
- }
-
- /* remember where we were in which buffer before we change things */
- if (current_buffer != XBUFFER (binfo->emacs_buffer))
- {
- record_unwind_protect (save_excursion_restore, save_excursion_save ());
- Fset_buffer (binfo->emacs_buffer);
- }
-
- /* set default-directory */
- if (!NILP (pathname_directory))
- {
- if (!NILP (Ffile_directory_p (pathname_directory))
- && !NILP (Ffile_executable_p (pathname_directory)))
- Fset (Qdefault_directory, pathname_directory);
- /* Never set this to nil, that loses badly. */
- /* else
- Fset (Qdefault_directory, Qnil); */
- }
-
- /* set file name unless it's a directory */
- if (!NILP (pathname) && NILP (Ffile_directory_p (pathname)))
- {
- filename = Fexpand_file_name (pathname, Qnil);
- Fset (Qbuffer_file_name, filename);
- }
-
- /* set buffer name */
- if (!NILP (buffer_name))
- {
- if (modifying_p
- && strcmp ((char*)string_data (XSTRING (buffer_name)),
- (char*)
- string_data (XSTRING (XBUFFER (binfo->emacs_buffer)->name))))
- rename_the_buffer (buffer_name);
- }
-
- if (modifying_p)
- {
- call1 (Vrun_hooks, Venergize_kernel_modification_hook);
- /* Make sure buffer is current after the hook */
- Fset_buffer (binfo->emacs_buffer);
- }
-
- modified_buffer_flag = Fbuffer_modified_p (binfo->emacs_buffer);
-
- /* enables buffer edits */
- restore_buffer_state_cons =
- Fcons (make_opaque_ptr ((void *) cbu->bufferId),
- Fcons (XBUFFER (binfo->emacs_buffer)->read_only, Qt));
- record_unwind_protect (restore_buffer_state, restore_buffer_state_cons);
- XBUFFER (binfo->emacs_buffer)->read_only = Qnil;
-
- /* any changes here should take place "underneath" these hooks, I think */
- specbind (Qenergize_buffer_modified_hook, Qnil);
- specbind (Qfirst_change_hook, Qnil);
- specbind (Qbefore_change_functions, Qnil);
- specbind (Qbefore_change_function, Qnil); /* #### */
- /* As energize does not use the after-change-function it's not useful to
- bind it to NIL */
- /* specbind (Qafter_change_functions, Qnil); */
- /* specbind (Qafter_change_function, Qnil); #### */
- record_unwind_protect (restore_inside_parse_buffer,
- make_number (inside_parse_buffer));
- inside_parse_buffer = 1;
- specbind (Qbuffer_undo_list, Qt);
-
- XBUFFER (binfo->emacs_buffer)->undo_list = Qt;
-
- /* BufposForEnergizePos uses the current-buffer */
- from = BufposForEnergizePos (delete_from, binfo);
- to = BufposForEnergizePos (delete_to, binfo);
-
- /* See if we should get the characters from the file directly.
- Only protocol 0.10+ will do this.
- */
- #ifdef ENERGIZE_V2_HEADERS
- get_chars_from_file = 0;
- #else
- if (cbu->flags != 0xff)
- get_chars_from_file = cbu->flags & CBFileYourself;
- else
- get_chars_from_file = binfo->flags & CBFileYourself;
- #endif
-
- /* Even when we get the chars from a file there is an empty text string */
- if (get_chars_from_file)
- {
- text = CGetVstring (conn, &text_len);
- text = NULL;
- text_len = 0;
- }
- else
- {
- text = CGetVstring (conn, &text_len);
- }
-
- /* updates the visited file modtime */
- if (modifying_p && (from != to || text_len)
- /* but only when we do not read the file ourselves */
- && !get_chars_from_file)
- Fset_buffer_modtime (binfo->emacs_buffer, Qnil);
-
- if (!modifying_p)
- {
- /* clears the buffer in case we re-use a non-energize buffer */
- previous_point = 1;
- Fset_buffer (binfo->emacs_buffer);
- buffer_delete_range (current_buffer, BUF_BEG (current_buffer), BUF_Z (current_buffer), 0);
- }
- else
- {
- #if 1
- display_window = Fget_buffer_window (binfo->emacs_buffer, Qnil, Qnil);
- #endif
- previous_point = BUF_PT (current_buffer);
-
- #if 1
- if (!NILP (display_window))
- display_start =
- XINT (Fmarker_position (XWINDOW (display_window)->start));
- #endif
-
- if (from != to)
- {
- struct buffer *buf = XBUFFER (binfo->emacs_buffer);
-
- Fset_buffer (binfo->emacs_buffer);
- Fwiden (Fcurrent_buffer ());
- if (!NILP (binfo->output_mark)
- && marker_position (binfo->output_mark) >= from)
- Fset_marker (binfo->output_mark, make_number (from),
- binfo->emacs_buffer);
- if (((to - from) == text_len) && !get_chars_from_file &&
- !string_buffer_compare (text, text_len, buf, from))
- /* the new text is the same as the old text, don't clear
- the undo list*/
- {
- Fsetcdr (Fcdr (restore_buffer_state_cons), Qnil);
- no_text_deleted = 1;
- destroy_all_energize_extents (buf);
- }
- else
- {
- /* Do not keep window start if we actually delete text */
- should_keep_window_start = 0;
- Fset_buffer (binfo->emacs_buffer);
- destroy_all_energize_extents (buf);
- if (!get_chars_from_file)
- buffer_delete_range (current_buffer, from, to, 0);
- }
-
- /* Do not clear the undo list if getting the chars from the file */
- if (get_chars_from_file)
- Fsetcdr (Fcdr (restore_buffer_state_cons), Qnil);
- }
- else if (!text_len && !get_chars_from_file)
- /* if there is no text and we didn't delete anything,
- don't clear the undo_list slot */
- Fsetcdr (Fcdr (restore_buffer_state_cons), Qnil);
-
- }
-
- /* buffer type */
- if (cbu->flags != 0xff && cbu->flags != binfo->flags)
- {
- if (!modifying_p)
- {
- if (cbu->flags == CBUserInput)
- {
- Lisp_Object buffer_local_variable_name =
- Qenergize_user_input_buffer_mark;
- binfo->output_mark = Fmake_marker ();
- Fset_marker (binfo->output_mark, make_number (1),
- binfo->emacs_buffer);
- /* make sure that this guy doesn't get GC'd out from under us */
- Fmake_local_variable (buffer_local_variable_name);
- Fput (buffer_local_variable_name, Qpermanent_local, Qt);
- Fset (buffer_local_variable_name, binfo->output_mark);
- /* Make sure buffer is current after the hook */
- Fset_buffer (binfo->emacs_buffer);
- }
- }
- binfo->flags = cbu->flags;
- }
-
- if (get_chars_from_file && text_len != 0)
- /* I think this is always true, but let's make sure - jwz */
- abort ();
-
- if (text_len)
- {
- if (!NILP (binfo->output_mark))
- {
- Fset_buffer (binfo->emacs_buffer);
- if (XMARKER (binfo->output_mark)->buffer)
- Fgoto_char (binfo->output_mark, Fcurrent_buffer ());
- else
- /* This should not happen */
- Fgoto_char (make_number (BUF_ZV (XBUFFER (binfo->emacs_buffer))),
- Fcurrent_buffer ());
-
- if (BUF_PT (current_buffer) <= previous_point)
- {
- #if 1
- display_start += text_len;
- #endif
- previous_point += text_len;
- }
- buffer_insert_raw_string (current_buffer, text, text_len);
- Fset_marker (binfo->output_mark, make_number (BUF_PT (current_buffer)),
- binfo->emacs_buffer);
- }
- else if (modifying_p)
- {
- Fgoto_char (make_number (from), Fcurrent_buffer ());
- if (!no_text_deleted)
- buffer_insert_raw_string (current_buffer, text, text_len);
- }
- else
- buffer_insert_raw_string (current_buffer, text, text_len);
-
- previous_point = XINT (Fgoto_char (make_number (previous_point)),
- Fcurrent_buffer ());
- }
- else if (get_chars_from_file && !modifying_p)
- {
- /* !modifying_p means the buffer is being created - read the text
- from the file. */
- Finsert_file_contents_internal (Fbuffer_file_name (binfo->emacs_buffer),
- Qt, Qnil, Qnil, Qnil));
- }
-
- if (!relative_p)
- extent_offset = 0;
- else if (!NILP (binfo->output_mark))
- extent_offset = EnergizePosForBufpos (XINT (Fmarker_position
- (binfo->output_mark)),
- binfo);
- else
- extent_offset = EnergizePosForBufpos (BUF_Z(XBUFFER(binfo->emacs_buffer)),
- binfo);
-
- #if 1
- if (text_len || !text)
- hack_window_point (display_window,
- make_number (previous_point),
- make_number (display_start),
- should_keep_window_start,
- binfo);
- #endif
-
-
- /* Classes, generics and extents */
- /* make sure that we have enough room in the hash table */
- expand_hashtable (binfo->id_to_object,
- cbu->nClass + cbu->nGeneric + cbu->nExtent);
- read_energize_class_data (conn, cbu->nClass, binfo, modifying_p);
- read_energize_generic_data (conn, cbu->nGeneric, binfo, modifying_p);
- read_energize_extent_data (conn, cbu->nExtent, binfo, modifying_p, extent_offset);
-
- /* Restore the modified bit */
- Fset_buffer_modified_p (modified_buffer_flag, binfo->emacs_buffer);
-
- if (get_chars_from_file && modifying_p)
- {
- /* modifying_p means the buffer already exists and the extents are
- being re-written. It may be that the file has changed on disk,
- and the extents no longer correspond to the text in the buffer,
- which would be bad. So, check the file on disk, and if it has
- changed, offer to revert.
-
- As this runs lisp code which may prompt the user, and consequently
- may accept process output, be careful to do this after we have
- finished reading the current request from the Energize connection.
- */
- if (NILP (Fverify_visited_file_modtime (binfo->emacs_buffer)))
- {
- call1 (Qenergize_auto_revert_buffer, binfo->emacs_buffer);
- hack_window_point (display_window,
- make_number (previous_point),
- make_number (display_start),
- 1,
- binfo);
- }
- }
-
-
- /* restore modified hooks and globals, and return the previous buffer */
- UNGCPRO;
- unbind_to (speccount, Qnil);
- }
-
-
- static void
- cleanly_destroy_all_widgets (int count, LWLIB_ID *ids)
- {
- /* This just calls lw_destroy_all_widgets, but is careful to make sure that
- this doesn't cause the frames to shrink. If one deletes psheets
- (children of the "control" area of the MainWindow) without first
- unmanaging the MainWindow, the frame resizes. So first unmanage all
- the MainWindows of all applicable frames, then remanage them. This is
- nasty, but...
- */
- Lisp_Object tail;
- struct frame *f;
- int i, j;
-
- if (count == 0) return;
- for (tail = DEVICE_FRAME_LIST (get_x_device(Qnil));
- CONSP (tail); tail = XCDR (tail))
- {
- Lisp_Object frame = XCAR (tail);
- if (!FRAMEP (frame))
- continue;
- f = XFRAME (frame);
- if (!FRAME_IS_X (f))
- continue;
- /* Optimization: only unmanage the MainWindow if this frame is
- displaying one of the psheets in question. (Special casing
- the debugger panel as usual...)
- */
- for (i = 0; i < count; i++)
- if (ids [i] == debuggerpanel_sheet)
- {
- XtUnmanageChild (FRAME_X_CONTAINER_WIDGET (f));
- goto next_frame;
- }
- else
- for (j = 0; j < FRAME_X_CURRENT_PSHEET_COUNT (f); j++)
- if (ids [i] == FRAME_X_CURRENT_PSHEETS (f) [j])
- {
- XtUnmanageChild (FRAME_X_CONTAINER_WIDGET (f));
- goto next_frame;
- }
- next_frame: ;
- }
-
- for (i = 0; i < count; i++)
- {
- lw_destroy_all_widgets (ids [i]);
- if (ids [i] == debuggerpanel_sheet)
- {
- debuggerpanel_sheet = 0;
- desired_debuggerpanel_exposed_p = 0;
- }
- }
-
- for (tail = DEVICE_FRAME_LIST (get_x_device(Qnil)); CONSP (tail); tail = XCDR (tail))
- {
- Lisp_Object frame = XCAR (tail);
- if (!FRAMEP (frame))
- continue;
- f = XFRAME (frame);
- if (!FRAME_IS_X (f))
- continue;
- XtManageChild (FRAME_X_CONTAINER_WIDGET (f));
- }
- }
-
-
- /* kill an Energize buffer */
- static void
- forget_buffer (BufferInfo *binfo)
- {
- int i;
- Lisp_Object buffer = binfo->emacs_buffer;
-
- remove_buffer_info (binfo->id, buffer, binfo->editor);
- Venergize_buffers_list = Fdelq (buffer, Venergize_buffers_list);
-
- /* if there was an associated frame */
- if (!NILP (binfo->frame))
- Fdelete_frame (binfo->frame);
-
- if (binfo->n_p_sheets > 0)
- {
- /* Also delete the dialog boxes associated with the buffer. */
- cleanly_destroy_all_widgets (binfo->n_p_sheets,
- (LWLIB_ID *) binfo->p_sheet_ids);
- }
-
- free_buffer_info (binfo);
-
- XBUFFER (buffer)->undo_list = Qnil;
- /* flush the buffer SOE before flushing the extents */
- free_buffer_cached_stack (XBUFFER (buffer));
- XBUFFER (buffer)->extents = Qnil;
- }
-
- /********************** Request-related utilities ************************/
-
- /* outputs a single extent in the connection buffer */
- static void
- write_energize_extent_data (Connection *conn, Energize_Extent_Data *ext,
- unsigned int start, unsigned int end)
- {
- switch (ext->extentType)
- {
- case CEAttribute:
- CWriteExtent (conn, CEAttribute, ext->id, start, end,
- (EId)ext->u.attr.attrValue);
- break;
-
- case CEAbbreviation:
- CWriteExtent (conn, CEAbbreviation, ext->id, start, end,
- (EId)ext->u.abbrev.isOpened);
- break;
-
- case CEGeneric:
- CWriteExtent (conn, CEGeneric, ext->id, start, end, 0);
- break;
-
- case CEWriteProtect:
- CWriteExtent (conn, CEWriteProtect, ext->id, start, end, 0);
- break;
- }
- }
-
- /* Function called by map_extents in SaveBufferToEnergize. Outputs the
- extents for the extents corresponding to Energize objects, and
- increments the n_extents count. */
-
- static int
- write_energize_extent_data_mapper (EXTENT extent, void *arg)
- {
- binfo_and_n_extents *bane = (binfo_and_n_extents*)arg;
- Lisp_Object extent_obj;
- Energize_Extent_Data *ext;
-
- XSETEXTENT (extent_obj, extent);
- ext = extent_to_data (extent_obj);
- if (ext)
- {
- Bufpos first = XINT (Fextent_start_position (extent_obj));
- Bufpos last = XINT (Fextent_end_position (extent_obj));
- write_energize_extent_data (bane->binfo->editor->conn, ext,
- EnergizePosForBufpos (first, bane->binfo),
- EnergizePosForBufpos (last, bane->binfo));
- bane->n_extents += 1;
- }
- return 0;
- }
-
- /* Sends a BufferSaved request to energize for binfo */
- static void
- write_energize_buffer_data (BufferInfo *binfo)
- {
- Connection *conn = binfo->editor->conn;
- EId bufferId = binfo->id;
- CBuffer *cbu;
- CEditorRequest *req;
- struct buffer *cur_buff = current_buffer;
- int speccount = specpdl_depth ();
- Lisp_Object file_name;
-
- binfo_and_n_extents bane;
-
- /* selects the buffer as current */
- Fset_buffer (binfo->emacs_buffer);
-
- /* write header */
- cbu = CWriteBufferSavedHeader (conn);
- cbu->bufferId = bufferId;
- cbu->flags = 0;
- cbu->nClass = 0;
- cbu->nGeneric = 0;
-
- /* file name */
- file_name = current_buffer->filename;
- if (STRINGP (file_name))
- CWriteVstring0 (conn, string_data (XSTRING (file_name)));
- else
- CWriteVstring0 (conn, "");
- CWriteVstring0 (conn, ""); /* directory name */
- CWriteVstring0 (conn, ""); /* buffer name */
-
- /* write the text */
- #ifndef ENERGIZE_V2_HEADERS
- if (binfo->flags & CBFileYourself)
- {
- /* Only the 0.10+ protocol will ask us to write the file directly. */
- Lisp_Object start;
- Lisp_Object end;
- XSETINT (start, BUF_BEG (current_buffer));
- XSETINT (end, BUF_Z (current_buffer));
- Fwrite_region_internal (start, end,
- Fbuffer_file_name (binfo->emacs_buffer),
- Qnil, Qt);
- CNeedOutputSize (conn, 9);
- CWriteVstringLen (conn, NULL, 0);
- }
- else
- #endif /* ENERGIZE_V2_HEADERS */
- {
- Lisp_Object string = make_string_from_buffer (current_buffer,
- BUF_BEG (current_buffer),
- BUF_Z (current_buffer));
- CNeedOutputSize (conn, string_length (XSTRING (string)) + 9);
- CWriteVstringLen (conn, string_data (XSTRING (string)),
- string_length (XSTRING (string)));
- }
-
- /* write the extents */
- bane.binfo = binfo;
- bane.n_extents = 0;
-
- /* Only write the extents when not filing ourselves */
- #ifndef ENERGIZE_V2_HEADERS
- if (!(binfo->flags & CBFileYourself))
- #endif
- {
- map_extents (BUF_BEG (current_buffer), BUF_Z (current_buffer),
- write_energize_extent_data_mapper, &bane,
- binfo->emacs_buffer, 0, ME_END_CLOSED);
-
- }
-
- /* update nextent in request's header */
- req = (CEditorRequest *)conn->header;
- req->buffersaved.buffer.nExtent = bane.n_extents;
- CWriteLength (conn);
- CWriteRequestBuffer (conn);
-
- /* sets the flags so that we will warn Energize about more modifications */
- binfo->modified_state = 0;
-
- /* Mark the buffer as non editable so that we will ask Energize about it
- before modifying it again */
- binfo->editable = 0;
-
- /* restores the buffer as current */
- set_buffer_internal (cur_buff);
- unbind_to (speccount, Qnil);
- }
-
- static unsigned long
- energize_extent_data_id (Energize_Extent_Data *ext)
- {
- return ext ? ext->id : 0;
- }
-
-
- /********************** Menu ("keywords") operations **********************/
-
- static int
- something_answered_p (void* arg)
- {
- struct reply_wait* rw = (struct reply_wait*)arg;
- return rw->answered_p || !energize_connection || !energize_connection->conn;
- }
-
-
- static void
- push_wait (struct reply_wait* rw)
- {
- rw->next = global_reply_wait;
- global_reply_wait = rw;
- }
-
- static Lisp_Object
- remove_wait (Lisp_Object obj)
- {
- struct reply_wait* gw;
- struct reply_wait* previous;
- struct reply_wait* rw = (struct reply_wait *) get_opaque_ptr (obj);
-
- for (previous = 0, gw = global_reply_wait;
- gw != rw;
- previous = gw, gw = gw->next);
- if (previous)
- previous->next = gw->next;
- else
- global_reply_wait = gw->next;
- return Qnil;
- }
-
- static struct reply_wait*
- find_wait_reply (int serial)
- {
- struct reply_wait* gw;
- for (gw = global_reply_wait; gw && gw->serial != serial; gw = gw->next);
- return gw;
- }
-
-
- static int
- wait_for_reply (struct reply_wait* rw)
- {
- int speccount = specpdl_depth ();
- rw->answered_p = 0;
- push_wait (rw);
- record_unwind_protect (remove_wait, make_opaque_ptr (rw));
- wait_delaying_user_input (something_answered_p, rw);
- unbind_to (speccount, Qnil);
- return rw->answered_p;
- }
-
- /* gets the menu for the buffer/extent pair at the head of the request buffer.
- returns the propose choice request if succeeds, nil otherwise (kernel
- connection closed, or not connected)
- */
-
- static Lisp_Object
- get_energize_menu (Lisp_Object buffer, Lisp_Object extent_obj, int selection_p,
- Lisp_Object only_name)
- {
- Connection* conn;
- EId buffer_id;
- EId extent_id;
- Lisp_Object result;
- struct reply_wait rw;
- struct gcpro gcpro1, gcpro2;
-
- if (!get_energize_connection_and_buffer_id (buffer,
- (void **) &conn,
- (long *) &buffer_id))
- return Qnil;
-
- if (EXTENTP (extent_obj))
- extent_id = energize_extent_data_id (extent_to_data (extent_obj));
- else
- extent_id = 0;
-
- CWriteQueryChoicesRequest (conn, buffer_id, extent_id);
- conn->header->data =
- selection_p ? CEChasCharSelection | CEChasObjectSelection : 0;
- conn->header->serial = ++request_serial_number;
- CWriteRequestBuffer (conn);
-
- /* wait for the acknowledge */
- rw.serial = request_serial_number;
- rw.objectId = buffer_id;
- rw.genericId = extent_id;
- rw.menu_result = Qnil;
- rw.only_name = only_name;
-
- GCPRO2 (rw.menu_result, rw.only_name);
- wait_for_reply (&rw);
- result = rw.menu_result;
- UNGCPRO;
- return result;
- }
-
-
- static void
- execute_energize_menu (Lisp_Object buffer, Energize_Extent_Data* ext,
- char* name, EId item_id, EId flags,
- Lisp_Object selection, Lisp_Object no_confirm)
- {
- Connection* conn;
- EId buffer_id;
- EId extent_id;
- BufferInfo* binfo;
- struct reply_wait rw;
-
- if (!get_energize_connection_and_buffer_id (buffer, (void**)&conn,
- (long*)&buffer_id))
- return;
-
- extent_id = energize_extent_data_id (ext);
-
- if ((flags & CKBuffer) && !NILP (Fbuffer_modified_p (buffer)))
- {
- /* saves buffer if requested and needed */
- binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection);
- if (binfo)
- write_energize_buffer_data (binfo);
- }
-
- CWriteExecuteChoicesRequest (conn, buffer_id, extent_id, item_id, 0, 0);
- /* send the menu name */
- if (energize_connection->minor >= 7)
- CWriteVstring0 (conn, name);
- conn->header->serial = ++request_serial_number;
- conn->header->data = 0;
- if (STRINGP (selection))
- {
- conn->header->data |= CEChasCharSelection;
- CWriteVstringLen (conn, string_data (XSTRING (selection)),
- string_length (XSTRING (selection)));
- }
- else if (VECTORP (selection))
- {
- int i;
- EId data;
- conn->header->data |= CEChasObjectSelection;
-
- /* writes the length */
- data = vector_length (XVECTOR (selection));
- CWrite (conn, EId, &data);
-
- /* writes the elements */
- for (i = 0; i < vector_length (XVECTOR (selection)); i++)
- {
- if (CONSP (vector_data (XVECTOR (selection)) [i]))
- data = lisp_to_word (vector_data (XVECTOR (selection)) [i]);
- else
- data = XINT (vector_data (XVECTOR (selection)) [i]);
- CWrite (conn, EId, &data);
- }
- }
- else if (CONSP (selection))
- {
- Lisp_Object type = Fcar (selection);
- Lisp_Object value = Fcdr (selection);
- if (EQ (type, intern ("ENERGIZE_OBJECT"))
- && STRINGP (value))
- {
- conn->header->data |= CEChasObjectSelection;
- CWriteN (conn, char, string_data (XSTRING (value)),
- string_length (XSTRING (value)));
- }
- }
- else if (!NILP (selection))
- error ("unrecognised energize selection");
-
- if (!NILP (no_confirm))
- conn->header->data |= CECnoConfirm;
- CWriteLength (conn);
- CWriteRequestBuffer (conn);
-
- /* wait for the acknowledge */
- rw.serial = request_serial_number;
- rw.objectId = buffer_id;
- rw.genericId = extent_id;
- rw.itemId = item_id;
- rw.message = 0;
-
- if (wait_for_reply (&rw) && !rw.status)
- {
- char message [128];
- if (energize_connection && energize_connection->conn)
- sprintf (message, IDENTITY_CRISIS " command failed: %.80s",
- (rw.message ? rw.message : "(null)"));
- else
- sprintf (message, "Connection to " IDENTITY_CRISIS " was closed.");
- if (rw.message)
- xfree (rw.message);
- error (message);
- }
- else
- {
- if (rw.message)
- xfree (rw.message);
- if (!energize_connection)
- error ("Connection to " IDENTITY_CRISIS " was closed.");
- }
- }
-
- /* Returns a list of vectors representing the menu choices. Next request
- in connection must be a ProposeChoices. The list is
- (buffer extent <item1> ... <itemN>). <itemI> is (name id1 id2 flags).
- Idi is (high . low). We build the list in reverse order and nreverse
- it. If (only_name != 0), we only return the item of named only_name as
- a vector. */
-
- static Lisp_Object
- list_choices (Lisp_Object buffer, Lisp_Object extent_obj,
- Lisp_Object only_name, CProposeChoicesRequest* creq)
- {
- Connection *conn;
- int i;
- Lisp_Object item_list;
- Lisp_Object item;
- struct Lisp_Vector *v;
- struct gcpro gcpro1, gcpro2, gcpro3;
- CChoice *choice;
- ReqLen name_length;
- char *name;
- char *arg_name;
-
- if (energize_connection && energize_connection->conn)
- conn = energize_connection->conn;
- else
- return Qnil;
-
- if (!creq || creq->head.reqType != ProposeChoicesRType)
- {
- CSkipRequest (conn);
- return Qnil;
- }
-
- item = Qnil;
- item_list = Qnil;
-
- GCPRO3 (only_name, item_list, item);
-
- for (i = 0; i < (int)(creq->nChoices); i++)
- {
- choice = CGet (conn, CChoice);
- name = CGetVstring (conn, &name_length);
- if (!name_length)
- continue;
-
- /* the argument, if passed, is another string after the NUL (!)
- * this is a quick hack to provide cheap arguments to menus entries */
- arg_name = strchr (name, 0240);
- if (arg_name)
- {
- *arg_name= 0;
- arg_name += 1;
- }
-
- if (!NILP (only_name))
- {
- if (!strcmp ((char*) string_data (XSTRING (only_name)), name))
- {
- if (NILP (item))
- {
- item = make_vector (5, Qnil);
- v = XVECTOR (item);
- v->contents [0] = only_name;
- }
- v->contents [1] = word_to_lisp (choice->choiceId);
- v->contents [2] = Qnil;
- v->contents [3] = make_number (choice->flags);
- v->contents [4] = arg_name ? build_string (arg_name) : Qnil;
- }
- }
- else
- {
- item = make_vector (5, Qnil);
- v = XVECTOR (item);
- v->contents [0] = build_string (name);
- v->contents [1] = word_to_lisp (choice->choiceId);
- v->contents [2] = Qnil;
- v->contents [3] = make_number (choice->flags);
- v->contents [4] = arg_name ? build_string (arg_name) : Qnil;
- item_list = Fcons (item, item_list); /* pushes in the list */
- }
- }
-
- if (NILP (only_name))
- item_list = Fcons (buffer, Fcons (extent_obj, Fnreverse (item_list)));
- UNGCPRO;
-
- return NILP (only_name) ? item_list : item;
- }
-
- DEFUN ("energize-list-menu", Fenergize_list_menu,
- Senergize_list_menu, 3, 4, 0,
- "Request the set of menu options from the Energize server that are\n\
- appropriate to the buffer and the extent. Extent can be (), in which case\n\
- the options are requested for the whole buffer. Selection-p tells\n\
- if the selection is available on the dislpay emacs is using. \n\
- Returns the options as\n\
- a list that can be passed to energize-activate-menu. Items\n\
- in the list can also be passed to energize-execute-menu-item.\n\
- The list is (buffer extent or () <item1> ... <itemN>).\n\
- where <itemI> is (name id1 id2 flags); idI is (high . low).\n\
- If optional argument only-name is provided only the item with name only-name\n\
- is returned, or () if no such item exists.")
- (buffer, extent_obj, selection_p, only_name)
- Lisp_Object buffer, extent_obj, selection_p, only_name;
- {
- Lisp_Object res;
- CHECK_BUFFER (buffer, 1);
-
- if (!energize_connection || !energize_connection->conn) return Qnil;
-
- if (!NILP (only_name))
- CHECK_STRING (only_name, 1);
-
- res = get_energize_menu (buffer, extent_obj, !NILP (selection_p),
- only_name);
- notify_delayed_requests ();
- return res;
- }
-
- DEFUN ("energize-execute-menu-item", Fenergize_execute_menu_item,
- Senergize_execute_menu_item, 3, 5, 0,
- "Item is a vector received by energize-list-menu. Sends a request to\n\
- execute the code associated to this menu inside the Energize server.\n\
- Optional fourth argument is a string or a vector to be used as the selection\n\
- for entry disabled because they need the selection.\n\
- Optional fifth argument, if non NIL, tells Energize to not request \n\
- confirmation before executing the command.")
- (buffer, extent_obj, item, selection, no_confirm)
- Lisp_Object buffer, extent_obj, item, selection, no_confirm;
- {
- struct Lisp_Vector *v;
-
- if (!energize_connection || !energize_connection->conn) return Qnil;
-
- CHECK_BUFFER (buffer, 1);
- CHECK_VECTOR (item, 1);
- v = XVECTOR (item);
-
- if (vector_length (v) != 4)
- error ("Bad menu item to energize-execute-menu-item");
-
- /* ignore the flags for now */
- execute_energize_menu (buffer, extent_to_data (extent_obj),
- (char*)string_data (XSTRING (v->contents [0])),
- lisp_to_word (v->contents [1]),
- XINT (v->contents [3]),
- selection,
- no_confirm);
-
- return Qt;
- }
-
- DEFUN ("energize-execute-command-internal", Fenergize_execute_command_internal,
- Senergize_execute_command_internal, 3, 5, 0,
- "Command is a string naming an energize command. Sends a request to\n\
- execute this command inside the Energize server.\n\
- Optional fourth argument is a string or a vector to be used as the selection.\n\
- Optional fifth argument, if non NIL, tells Energize to not request \n\
- confirmation before executing the command.\n\
- \n\
- See also 'energize-list-menu'.")
- (buffer, extent_obj, command, selection, no_confirm)
- Lisp_Object buffer, extent_obj, command, selection, no_confirm;
- {
- if (!energize_connection || !energize_connection->conn) return Qnil;
-
- CHECK_BUFFER (buffer, 1);
- CHECK_STRING (command, 1);
-
- execute_energize_menu (buffer, extent_to_data (extent_obj),
- (char*)string_data (XSTRING (command)), 0, 0, selection,
- no_confirm);
-
- return Qt;
- }
-
- /********************************* kill buffer interface ****************/
-
- DEFUN ("energize-buffer-type-internal",
- Fenergize_buffer_type, Senergize_buffer_type,
- 1, 1, 0,
- "Return a symbol denoting the buffer type if buffer is an Energize\n\
- buffer, else it returns NIL.")
- (buffer)
- Lisp_Object buffer;
- {
- if (!energize_connection) return Qnil;
-
- CHECK_BUFFER (buffer, 1);
- return get_buffer_type_for_emacs_buffer (buffer, energize_connection);
- }
-
- DEFUN ("set-energize-buffer-type-internal",
- Fset_energize_buffer_type_internal,
- Sset_energize_buffer_type_internal, 2, 2, 0,
- "Return the type symbol which is the new buffer-type, if the buffer is\n\
- an Energize buffer and the type is non-NIL symbol, else it returns NIL.")
- (buffer, type)
- Lisp_Object buffer, type;
- {
- BufferInfo *binfo;
-
- if (!energize_connection || (NILP (type))) return Qnil;
-
- CHECK_BUFFER (buffer, 1);
- CHECK_SYMBOL (type, 1);
-
- if (!(binfo =
- get_buffer_info_for_emacs_buffer (buffer, energize_connection)))
- return Qnil;
- else
- return
- set_buffer_type_for_emacs_buffer (buffer, energize_connection, type);
- }
-
- DEFUN ("energize-buffer-p", Fenergize_buffer_p, Senergize_buffer_p, 1, 1, 0,
- "Whether buffer is an Energize buffer.")
- (buffer)
- Lisp_Object buffer;
- {
- BufferInfo *binfo;
-
- if (!energize_connection) return Qnil;
-
- CHECK_BUFFER (buffer, 1);
- if (!(binfo =
- get_buffer_info_for_emacs_buffer (buffer, energize_connection)))
- return Qnil;
- else
- return Qt;
- }
-
- DEFUN ("energize-buffer-id", Fenergize_buffer_id, Senergize_buffer_id, 1, 1, 0,
- "Return (high . low) if buffer is an Energize buffer, otherwise nil.")
- (buffer)
- Lisp_Object buffer;
- {
- BufferInfo *binfo;
-
- if (!energize_connection) return Qnil;
-
- CHECK_BUFFER (buffer, 1);
- if (!(binfo =
- get_buffer_info_for_emacs_buffer (buffer, energize_connection)))
- return Qnil;
- else
- return word_to_lisp (binfo->id);
- }
-
- DEFUN ("energize-request-kill-buffer", Fenergize_request_kill_buffer,
- Senergize_request_kill_buffer, 1, 1, 0,
- "Sends a request to energize for killing buffer.")
- (buffer)
- Lisp_Object buffer;
- {
- BufferInfo *binfo;
-
- if (!energize_connection) return Qnil;
-
- CHECK_BUFFER (buffer, 1);
- if (!(binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection)))
- return Qnil;
-
- /* Tell Energize about it if connected */
- if (energize_connection->conn)
- {
- CWriteKillBufferHeader (energize_connection->conn, binfo->id);
- CWriteRequestBuffer (energize_connection->conn);
- }
-
- /* Clears the internal state */
- forget_buffer (binfo);
-
- return Qnil;
- }
-
- /******************** Handle requests from the kernel *********************/
-
- #ifdef EMACS_BTL
- #include "cadillac-btl-extern.h"
- #endif
-
- /* turn logging on or off, etc. */
- static void
- handle_logging_request (Editor *editor, CLoggingRequest *creq)
- /* I'm a lumberjack and I'm ok... */
- {
- ReqLen name_len;
- char* data_filename = CGetVstring (editor->conn, &name_len);
-
- #ifdef EMACS_BTL
- {
- char *execname =
- (STRINGP (Vinvocation_directory))?
- ((char *) string_data (XSTRING (Vinvocation_directory))):0;
-
- switch (creq->type)
- {
- case CLRInitBTL:
- cadillac_terminate_logging (); /* #### rename me */
- cadillac_initialize_backtrace_logging /* #### rename me */
- (data_filename, execname, (long) creq->limit, (long) creq->interval);
- break;
-
- case CLRInitPCL:
- cadillac_terminate_logging (); /* #### rename me */
- cadillac_initialize_pc_logging /* #### rename me */
- (data_filename, execname, (long) creq->limit, (long) creq->interval);
- break;
-
- case CLRStart:
- cadillac_start_logging (); /* #### rename me */
- break;
-
- case CLRStop:
- cadillac_stop_logging (); /* #### rename me */
- break;
-
- case CLRTerminate:
- cadillac_terminate_logging (); /* #### rename me */
- break;
-
- case CLRSetLogSignal:
- cadillac_set_log_signal (creq->signal); /* #### rename me */
- break;
-
- default:
- error ("Bad logging request type %d", creq->type);
- }
- }
- #else
- message ("Logging request, but no such code in image.");
- #endif
- }
-
-
-
- /* creates a new buffer */
- static void
- handle_new_buffer_request (Editor *editor, CNewBufferRequest *creq)
- {
- read_energize_buffer_data (editor->conn, &creq->buffer, editor, 0, 0,
- creq->transientId, 0);
- if (!NILP (Venergize_create_buffer_hook))
- {
- CBuffer *cbu = &creq->buffer;
- BufferInfo *binfo = get_buffer_info_for_id (cbu->bufferId, editor);
- Lisp_Object buffer;
- if (binfo)
- {
- Lisp_Object prev_frame;
- buffer = binfo->emacs_buffer;
- if (!NILP (binfo->frame))
- {
- prev_frame = Fselected_frame (Qnil);
- Fselect_frame (binfo->frame);
- }
- run_hook_with_args (Qenergize_create_buffer_hook, 1, buffer);
- if (!NILP (binfo->frame))
- Fselect_frame (prev_frame);
- }
- }
- }
-
- /* Modifies the contents of a buffer */
- static void
- handle_modify_buffer_request (Editor *editor, CModifyBufferRequest *creq)
- {
- read_energize_buffer_data (editor->conn, &creq->newData, editor,
- creq->startPosition, creq->endPosition,
- 0, creq->head.data);
- }
-
- static void
- make_buffer_and_extent_visible (Lisp_Object list, Lisp_Object go_there)
- {
- call2 (Qenergize_make_many_buffers_visible, list, go_there);
- }
-
- /* pops a buffer and scroll to a extent: calls to lisp */
- static void
- handle_ensure_visible_request (Editor *editor, CEnsureVisibleRequest *creq)
- {
- BufferInfo *binfo;
- Energize_Extent_Data *ext;
- Lisp_Object buffer_extent_list;
- struct gcpro gcpro1;
-
- buffer_extent_list = Qnil;
- GCPRO1 (buffer_extent_list);
-
- binfo = get_buffer_info_for_id (creq->bufferId, editor);
- if (!binfo)
- {
- message ("EnsureVisibleRequest: unknown buffer");
- goto finished;
- }
-
- if (!NILP (binfo->frame))
- {
- /* ignore ensure visible for postit note buffers */
- goto finished;
- }
-
- if (creq->extentId)
- {
- ext = get_extent_data (creq->extentId, binfo);
- if (!ext)
- message ("EnsureVisibleRequest: ignoring unknown extent");
- }
- else
- ext = 0;
-
- buffer_extent_list = Fcons (ext ? data_to_extent (ext) : Qnil, Qnil);
- buffer_extent_list = Fcons (binfo->emacs_buffer, buffer_extent_list);
-
- make_buffer_and_extent_visible (buffer_extent_list, creq->head.data ? Qt : Qnil);
-
- finished:
- CSkipRequest (editor->conn);
- UNGCPRO;
- }
-
- static void
- handle_ensure_many_visible_request (Editor *editor,
- CEnsureManyVisibleRequest *creq)
- {
- BufferInfo *binfo;
- Energize_Extent_Data *ext;
- Lisp_Object buffer_extent_list;
- int n;
- EId buffer_id;
- EId extent_id;
- struct gcpro gcpro1;
-
- buffer_extent_list = Qnil;
- GCPRO1 (buffer_extent_list);
-
- for (n = creq->head.data,
- buffer_id = creq->bufferId,
- extent_id = creq->extentId;
- n;
- n--,
- buffer_id = n ? *(CGet (editor->conn, EId)) : 0,
- extent_id = n ? *(CGet (editor->conn, EId)) : 0)
- {
- binfo = get_buffer_info_for_id (buffer_id, editor);
- if (!binfo)
- {
- message ("EnsureManyVisibleRequest: ignoring unknown buffer");
- continue;
- }
-
- if (!NILP (binfo->frame))
- {
- /* silently ignore ensure visible for postit note buffers */
- continue;
- }
-
- if (extent_id)
- {
- ext = get_extent_data (extent_id, binfo);
- if (!ext)
- message ("EnsureManyVisibleRequest: ignoring unknown extent");
- }
- else
- ext = 0;
-
- /* cons in reverse order and reverse the list before
- calling make_buffer_and_extent_visible */
- buffer_extent_list = Fcons (binfo->emacs_buffer, buffer_extent_list);
- buffer_extent_list = Fcons (ext ? data_to_extent (ext) : Qnil,
- buffer_extent_list);
- }
- buffer_extent_list = Fnreverse (buffer_extent_list);
- make_buffer_and_extent_visible (buffer_extent_list, Qt);
-
- UNGCPRO;
- }
-
- /* Update the cached menus, ie update the menubar for now. */
- static void
- handle_propose_choices_request (Editor *editor, CProposeChoicesRequest *req)
- {
- BufferInfo* binfo;
- Lisp_Object buffer = Qnil;
- Lisp_Object extent = Qnil;
- Lisp_Object choices = Qnil;
- struct gcpro gcpro1, gcpro2, gcpro3;
- struct reply_wait* rw;
-
- GCPRO3 (buffer, extent, choices);
-
- /* get the buffer */
- binfo = get_buffer_info_for_id (req->objectId, editor);
- if (binfo)
- buffer = binfo->emacs_buffer;
- else
- buffer = Qnil;
-
- /* get the extent */
- if (binfo && req->genericId)
- {
- Energize_Extent_Data* ext = get_extent_data (req->genericId, binfo);
- if (ext)
- extent = data_to_extent (ext);
- else
- extent = Qnil;
- }
- else
- extent = Qnil;
-
- /* find if we were waiting for a reply */
- rw = find_wait_reply (req->head.serial);
-
- /* handle the request */
- if (rw && rw->objectId == req->objectId && rw->genericId == req->genericId)
- {
- /* It's a reply for a get_energize_menu call */
- rw->answered_p = True;
- rw->status = 1;
- rw->menu_result = list_choices (buffer, extent, rw->only_name, req);
- }
- else
- {
- /* It's a menu update, call the hook */
- choices = list_choices (buffer, extent, Qnil, req);
- run_hook_with_args (Qenergize_menu_update_hook, 1, choices);
- }
- UNGCPRO;
- }
-
- /* Kills a buffer */
- static void
- unmodify_buffer_and_kill_it (Lisp_Object buffer)
- {
- int speccount = specpdl_depth ();
-
- if (!BUFFER_LIVE_P (XBUFFER (buffer)))
- return;
-
- Fset_buffer_modified_p (Qnil, buffer);
-
- /* kill it. This will call the Energize hook to do the right thing */
- Fkill_buffer (buffer);
- }
-
- static void
- handle_kill_buffer_request (Editor *editor, CKillBufferRequest *creq)
- {
- BufferInfo *binfo;
-
- if (!(binfo = get_buffer_info_for_id (creq->bufferId, editor)))
- {
- message ("KillBufferVisibleRequest: unregistered buffer");
- return;
- }
-
- unmodify_buffer_and_kill_it (binfo->emacs_buffer);
- }
-
- static void
- handle_remove_extents_request (Editor *editor, CRemoveExtentsRequest *creq)
- {
- BufferInfo *binfo;
- int i;
- EId *ids;
- Lisp_Object restore_buffer_state_cons;
- int speccount = specpdl_depth ();
-
- if (!(binfo = get_buffer_info_for_id (creq->bufferId, editor)))
- {
- message ("RemoveExtentsRequest: unregistered buffer");
- CSkipRequest (editor->conn);
- return;
- }
-
- /* enable buffer edits */
- restore_buffer_state_cons =
- Fcons (make_opaque_ptr ((void *) creq->bufferId),
- Fcons (XBUFFER (binfo->emacs_buffer)->read_only, Qnil));
-
- record_unwind_protect (restore_buffer_state, restore_buffer_state_cons);
-
- XBUFFER (binfo->emacs_buffer)->read_only = Qnil;
-
- /* save old hook values */
- specbind (Qenergize_buffer_modified_hook, Qnil);
-
- ids = CGetN (editor->conn, EId, creq->nExtent);
- for (i = 0; i < creq->nExtent; i++)
- {
- Energize_Extent_Data *ext = get_extent_data (ids [i], binfo);
- if (ext)
- free_Energize_Extent_Data (ext, binfo, OFT_STANDALONE);
- }
-
- /* restore modified hooks and globals */
- unbind_to (speccount, Qnil);
- }
-
- #ifndef ENERGIZE_V2_HEADERS
- static Lisp_Object
- save_to_energize_unwind (Lisp_Object closure)
- {
- BITS32 buffer_id = (BITS32) cons_to_long (closure);
- /* If the buffer ID is not 0, then the call to save-buffer
- didn't complete normally - so tell Energize the save was aborted. */
- if (buffer_id)
- {
- Editor *editor = energize_connection;
- if (editor && editor->conn) /* Maybe the kernel has gone away. */
- {
- CWriteBufferSaveAbortedHeader (editor->conn, buffer_id);
- CWriteRequestBuffer (editor->conn);
- }
- }
- return Qnil;
- }
- #endif /* ENERGIZE_V2_HEADERS */
-
-
- /* handles a request to save a buffer from the kernel */
- static void
- handle_save_buffer_request (Editor *editor, CSaveBufferRequest *creq)
- {
- BufferInfo *binfo;
- int speccount = specpdl_depth ();
- struct gcpro gcpro1;
- Lisp_Object closure = Qnil;
-
- if (!(binfo = get_buffer_info_for_id (creq->bufferId, editor)))
- {
- message ("Server attempt to save a non registered buffer");
- return;
- }
-
- if (!EQ (binfo->emacs_buffer, Fcurrent_buffer ()))
- {
- record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
- Fset_buffer (binfo->emacs_buffer);
- }
-
- GCPRO1 (closure);
- if (creq->head.data == CSExecuteSave)
- {
- #ifndef ENERGIZE_V2_HEADERS
- Lisp_Object closure = make_opaque_ptr ((void *) creq->bufferId);
- record_unwind_protect (save_to_energize_unwind, closure);
- #endif /* ENERGIZE_V2_HEADERS */
- call0 (intern ("save-buffer"));
- #ifndef ENERGIZE_V2_HEADERS
- /* clear out the id to tell the unwind-protect form that the save
- completed normally. */
- set_opaque_ptr (closure, 0);
- #endif /* ENERGIZE_V2_HEADERS */
- }
- else
- write_energize_buffer_data (binfo);
-
- UNGCPRO;
- unbind_to (speccount, Qnil);
- }
-
- static void
- handle_set_modified_flag_request (Editor* editor,
- CSetModifiedFlagRequest* creq)
- {
- BufferInfo *binfo;
- int speccount = specpdl_depth ();
-
- if (!(binfo = get_buffer_info_for_id (creq->bufferId, editor)))
- {
- message ("Server attempt to set modified flag of a non registered buffer");
- return;
- }
-
- record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
- specbind (Qenergize_buffer_modified_hook, Qnil);
-
- /* Only set buffer modified time in older protocols
- as we handle the file timestamps ourselves now for
- CBFileYourself buffers. */
- #ifndef ENERGIZE_V2_HEADERS
- if ((energize_connection->minor < 10) && !(binfo->flags & CBFileYourself))
- #endif
- {
- Fset_buffer_modtime (binfo->emacs_buffer, Qnil);
- }
-
- Fset_buffer_modified_p (creq->state ? Qt : Qnil, binfo->emacs_buffer);
- binfo->modified_state = creq->state;
- /* Mark the buffer so that we ask permission to Energize when the
- * user tries to modify it again */
- binfo->editable = 0;
- if (!creq->state)
- mark_all_extents_as_unmodified (binfo);
- unbind_to (speccount, Qnil);
- }
-
-
- /* handles requests regarding p_sheet associated to buffers */
- static void
- add_in_list_of_ids (int** ids, int* n_ids, int id)
- {
- if (*n_ids == 0)
- {
- *n_ids = 1;
- *ids = (int*)xmalloc (sizeof (int));
- }
- else
- {
- *n_ids += 1;
- *ids = (int*)xrealloc (*ids, sizeof (int) * (*n_ids));
- }
- (*ids) [(*n_ids) - 1] = id;
- }
-
- static void
- remove_from_list_of_ids (int** ids, int* n_ids, int id)
- {
- int i;
- if (*n_ids)
- {
- /* look for id in *ids */
- for (i = 0; i < (*n_ids) && (*ids) [i] != id; i++);
- /* shift the remaining ones */
- for (; i < (*n_ids) - 1; i++)
- (*ids) [i] = (*ids) [i + 1];
- /* decrease the count */
- *n_ids -= 1;
- /* free array if empty */
- if (!*n_ids)
- {
- xfree (*ids);
- *ids = 0;
- }
- }
- }
-
- extern void make_psheets_desired (struct frame *, Lisp_Object);
-
- static void
- handle_buffer_sheet_request (Editor *editor, CSheetRequest *sreq,
- EId buffer_id)
- {
- BufferInfo *binfo;
- char *name;
- Connection *conn = editor->conn;
-
- if (!(binfo = get_buffer_info_for_id (buffer_id, editor)))
- {
- message ("Server attempt to use p_sheet in a non registered buffer");
- CSkipRequest (conn);
- return;
- }
-
- name = CGetVstring (conn, (ReqLen *) 0);
- switch ((CSheetRSubtype) sreq->head.data)
- {
- case CSCreate:
- lw_register_widget (name, name, sreq->sheetId, NULL, NULL,
- handle_sheet_control_change, NULL);
- add_in_list_of_ids (&binfo->p_sheet_ids, &binfo->n_p_sheets,
- sreq->sheetId);
- if (!strcmp (name, DEBUGGER_PSHEET_NAME))
- debuggerpanel_sheet = sreq->sheetId;
- break;
-
- case CSDelete:
- remove_from_list_of_ids (&binfo->p_sheet_ids, &binfo->n_p_sheets,
- sreq->sheetId);
- cleanly_destroy_all_widgets (1, &sreq->sheetId);
- if (sreq->sheetId == debuggerpanel_sheet)
- {
- desired_debuggerpanel_exposed_p = 0;
- debuggerpanel_sheet = 0;
- }
- break;
-
- case CSHide:
- {
- struct frame *frame;
- Lisp_Object rest;
-
- if (sreq->sheetId == debuggerpanel_sheet)
- desired_debuggerpanel_exposed_p = 0;
- else
- for (rest = DEVICE_FRAME_LIST (get_x_device(Qnil)); !NILP (rest); rest = Fcdr (rest))
- {
- frame = XFRAME (Fcar (rest));
- if (FRAME_IS_X (frame))
- make_psheets_desired (frame, Qnil);
- }
- }
- break;
-
- case CSShow:
- if (sreq->sheetId == debuggerpanel_sheet)
- desired_debuggerpanel_exposed_p = 1;
- else
- {
- struct frame *frame;
- struct window *window;
- Lisp_Object rest;
- for (rest = DEVICE_FRAME_LIST (get_x_device(Qnil)); !NILP (rest); rest = Fcdr (rest))
- {
- frame = XFRAME (Fcar (rest));
- if (FRAME_IS_X (frame))
- {
- window = XWINDOW (frame->selected_window);
- if (EQ (window->buffer, binfo->emacs_buffer))
- make_psheets_desired (frame, binfo->emacs_buffer);
- }
- }
- }
- break;
- }
- }
-
-
-
- /* show busy */
-
- static void
- show_all_menubars_busy (int busy)
- {
- struct frame *f;
- Lisp_Object tail;
-
- for (tail = DEVICE_FRAME_LIST (get_x_device (Qnil)); CONSP (tail);
- tail = XCDR (tail))
- {
- f = XFRAME (XCAR (tail));
- if (FRAME_IS_X (f))
- {
- if (FRAME_X_MENUBAR_WIDGET (f))
- lw_show_busy (FRAME_X_MENUBAR_WIDGET (f), busy);
- }
- }
- }
-
- static void
- handle_show_busy_request (Editor *editor, CGenericRequest *preq)
- {
- /* call the show busy routine of the library for the menubar of
- * all frames */
- ReqLen len;
-
- char* why = CGetVstring (editor->conn, &len);
-
- show_all_menubars_busy (preq->head.data);
- Venergize_kernel_busy = preq->head.data ? Qt : Qnil;
- run_hook_with_args (Qenergize_kernel_busy_hook, 1, build_string (why));
- }
-
- /* This request creates, destroys, raises, or lowers a psheet or dialog box.
- */
- static void
- handle_sheet_request (Connection* conn, CSheetRequest* sreq, Widget parent)
- {
- char* name = CGetVstring (conn, NULL);
-
- switch ((CSheetRSubtype)sreq->head.data)
- {
- case CSCreate:
- lw_create_widget (name, name, sreq->sheetId, 0, parent,
- !sreq->bufferId, 0, handle_sheet_control_change, 0);
- break;
- case CSDelete:
- cleanly_destroy_all_widgets (1, &sreq->sheetId);
- break;
-
- case CSShow:
- lw_pop_up_all_widgets (sreq->sheetId);
- break;
-
- case CSHide:
- lw_pop_down_all_widgets (sreq->sheetId);
- break;
- }
- }
-
- /* This request changes slot values in the psheets/dialog boxes. */
- static void
- handle_set_control_request (Connection* conn, CGenericRequest* creq)
- {
- CSetControlRequest* sreq = &creq->setcontrol;
- widget_value val;
- widget_value* contents;
-
- unsigned long i;
- unsigned long n = sreq->nChoices;
-
- if (n > 0)
- {
- contents = (widget_value *) xmalloc (n * sizeof (widget_value));
- memset (contents, 0, (n * sizeof (widget_value)));
- }
- else
- contents = NULL;
- memset (&val, 0, sizeof (val));
- val.name = CGetVstring (conn, NULL);
- val.enabled = !(sreq->flags & CKInactive);
- val.selected = !!(sreq->flags & CKSelected);
- val.change = VISIBLE_CHANGE;
- val.contents = contents;
-
- for (i = 0; i < n; i++)
- {
- widget_value* cur = &contents [i];
- CChoice* choice = CGet (conn, CChoice);
- cur->name = CGetVstring (conn, NULL);
- cur->value = cur->name;
- cur->key = NULL;
- cur->enabled = !(choice->flags & CKInactive);
- cur->selected = !!(choice->flags & CKSelected);
- cur->change = VISIBLE_CHANGE;
- cur->contents = NULL;
- cur->call_data = NULL;
- cur->next = i == n - 1 ? NULL : &contents [i + 1];
- cur->toolkit_data = NULL;
- if ((i == 0 && n == 1) || cur->selected)
- {
- val.value = cur->name;
- if (!*val.value)
- val.value = NULL;
- }
- }
- lw_modify_all_widgets (sreq->sheetId, &val, True);
-
- if (contents)
- xfree (contents);
- }
-
- static void
- handle_sheet_control_change (Widget widget, EId sheet_id, void* arg)
- {
- Connection* conn;
- widget_value* val;
- widget_value* cur;
- widget_value* this_val = NULL;
- widget_value* cancel = NULL;
- char* this_name;
- int delete_window_p = (((int) arg) == -1);
-
-
- if (!energize_connection)
- return;
-
- conn = energize_connection->conn;
- if (!conn)
- return;
-
- this_name = XtName (widget);
- val = lw_get_all_values (sheet_id);
-
- if (delete_window_p)
- /* Complete and utter kludge. If this dbox was dismissed with the
- WM close box (WM_DELETE_WINDOW, meaning the widget was destroyed)
- then we look for a likely "cancel" button and pretend the user
- clicked on that. Really the protocol should be extended for this.
- */
- for (cur = val; cur; cur = cur->next)
- {
- char *v = cur->value;
- if (v &&
- ((strlen (v) >= 6 && !strncmp (v, "cancel", 6)) ||
- (strlen (v) >= 5 && !strncmp (v, "abort", 5))))
- cancel = cur;
- }
-
- /* first send all the edited widgets */
- for (cur = val; cur; cur = cur->next)
- {
- /* do not send the widget that ran the callback */
- if (!strcmp (cur->name, this_name))
- this_val = cur;
- else if (cur == cancel)
- ;
- /* send the edited widgets */
- else if (cur->edited)
- {
- char* value = cur->value;
- unsigned int flags = 0;
-
- if (!cur->enabled)
- flags |= CKInactive;
- if (cur->selected)
- flags |= CKSelected;
-
- /* the kernel is brain dead and expect "1" and "0" as values
- for the checkbox objects. So if value is NULL, make it be "0"
- or "1" depending on the selected state. This is until we fix
- the kernel. */
- if (!value)
- value = cur->selected ? "1" : "0";
-
- CWriteSetControlRequest (conn, sheet_id, 0, cur->name, 1);
- CWriteChoice (conn, 0, flags, value, 0);
- CWriteLength (conn);
- }
- }
-
- if (delete_window_p && !this_val)
- {
- this_val = cancel;
- /* if (! this_val) abort (); */
- }
-
- /* Then send the widget that ran the callback */
- if (this_val)
- {
- CWriteSetControlRequest (conn, sheet_id, 0, this_val->name, 1);
- CWriteChoice (conn, 0, 0, this_val->value, 0);
- CWriteLength (conn);
- CWriteRequestBuffer (conn);
- }
- }
-
- /******************** Low level connection stuff ************************/
- static void
- add_in_connection_input_buffer (Connection *conn, char *s, int l)
- {
- /* Should be in connection.c */
- if (conn->inread >= conn->infill)
- conn->inread = conn->infill = conn->inbuffer;
-
- CNeedInputSize (conn, l);
- memcpy (conn->infill, s, l);
- conn->infill += l;
- }
-
- static Lisp_Object
- process_one_energize_request ()
- {
- Editor *editor = energize_connection;
- CEditorRequest *req;
- int res = 0;
-
- if (!editor) return make_number (res);
-
- if (!editor->conn)
- {
- close_energize_connection ();
- return make_number (res);
- }
-
- req = CReadEditorRequest (editor->conn);
- if (!req)
- {
- switch (errno)
- {
- case EWOULDBLOCK:
- /* message ("ProcessEnergizeRequest: internal error EWOULDBLOCK"); */
- res = -1;
- break;
-
- case 0:
- case ECONNRESET:
- message ("Connection to " IDENTITY_CRISIS " was closed.");
- close_energize_connection ();
- break;
-
- default:
- message
- ("System error on connection to " IDENTITY_CRISIS ", closing.");
- close_energize_connection ();
- break;
- }
- }
- else
- {
- res = 1;
- switch (req->head.reqType)
- {
- case RefuseConnectionRType:
- message (IDENTITY_CRISIS " connection refused");
- close_energize_connection ();
- break;
-
- case AcceptConnectionRType:
- {
- CProtocol* proto = CGet (editor->conn, CProtocol);
- editor->major = proto->major;
- editor->minor = proto->minor;
- message (IDENTITY_CRISIS " connection accepted");
- CSkipRequest (editor->conn);
- }
- break;
-
- case NewBufferRType:
- handle_new_buffer_request (editor, &req->newbuffer);
- break;
-
- case QueryBufferRType:
- {
- EId buffer_id;
- struct reply_wait* rw = find_wait_reply (req->head.serial);
- CGetVstring (editor->conn, 0); /* skip directory */
- CGetVstring (editor->conn, 0); /* skip file */
- buffer_id = *CGet (editor->conn, EId);
- if (rw)
- {
- rw->answered_p = 1;
- rw->status = req->head.data;
- rw->objectId = buffer_id;
- }
- }
- break;
-
- case EnsureVisibleRType:
- handle_ensure_visible_request (editor, &req->ensurevisible);
- break;
-
- case EnsureManyVisibleRType:
- handle_ensure_many_visible_request (editor, &req->ensuremanyvisible);
- break;
-
- case ModifyBufferRType:
- handle_modify_buffer_request (editor, &req->modifybuffer);
- break;
-
- case ProposeChoicesRType:
- handle_propose_choices_request (editor,
- &req->generic.proposechoices);
- break;
-
- case ChoiceExecutedRType:
- {
- struct reply_wait* rw = find_wait_reply (req->head.serial);
- CChoiceExecutedRequest* ce = &req->generic.choiceexecuted;
- if (rw)
- {
- rw->answered_p = 1;
- rw->status = ce->head.data;
- rw->message = CMakeVstring (editor->conn, 0);
- }
- }
- break;
-
- case KillBufferRType:
- handle_kill_buffer_request (editor, &req->killbuffer);
- break;
-
- case ModifiedBufferRType:
- {
- struct reply_wait* rw = find_wait_reply (req->head.serial);
- if (rw)
- {
- rw->answered_p = 1;
- if (rw->objectId == req->modifiedbuffer.bufferId)
- rw->status = req->modifiedbuffer.state;
- else
- rw->status = CMBufferLocked;
- }
- }
- break;
-
- case SetModifiedFlagRType:
- handle_set_modified_flag_request (editor, &req->setmodifiedflag);
- break;
-
- case RemoveExtentsRType:
- handle_remove_extents_request (editor, &req->removeextents);
- break;
-
- case RenumberExtentsRType:
- /* HandleDuplicateExtentRequest (editor, req); */
- break;
-
- #if 0
- case DialogRType:
- /* HandleDialogRequest (editor, req, CurrentBuffer (editor)); */
- break;
- #endif
-
- case SaveBufferRType:
- handle_save_buffer_request (editor, &req->savebuffer);
- break;
-
- case SheetRType:{
- EId buffer_id = req->generic.sheet.bufferId;
- if (!buffer_id)
- buffer_id = buffer_id_of_sheet (req->generic.sheet.sheetId);
- if (buffer_id)
- handle_buffer_sheet_request (editor, &req->generic.sheet,
- buffer_id);
- else
- {
- CSheetRSubtype type = (CSheetRSubtype)req->head.data;
- if (type == CSDelete || type ==CSHide)
- /* #### ??? this does nothing. */
- Fselect_frame (Fselected_frame (Qnil));
- handle_sheet_request (editor->conn, &req->generic.sheet,
- FRAME_X_SHELL_WIDGET
- (XFRAME (Fselected_frame (Qnil))));
- }
- }
- break;
-
- case SetControlRType:
- handle_set_control_request (editor->conn, (CGenericRequest*) req);
- break;
-
- case OpenPostitRType:
- case KillPostitRType:
- message ("Don't know what to do with postit requests.");
- break;
-
- case ShowBusyRType:
- handle_show_busy_request (editor, (CGenericRequest*)req);
- break;
-
- case LoggingRType:
- handle_logging_request (editor, (CLoggingRequest*)req);
- break;
-
- #ifndef ENERGIZE_V2_HEADERS
- case KernelEventRType:
- CSkipRequest (editor->conn);
- break;
- #endif
-
- default:
- message("ProcessEnergizeRequest: can't handle request of type %d",
- req->head.reqType);
- }
-
- }
-
- return make_number (res);
- }
-
- static int inside_process_energize_request_1;
-
- /* this must be called ONLY by unwind_protect in process_energize_request_1 */
- static Lisp_Object
- post_handle_request (Lisp_Object ignored)
- {
- if (inside_process_energize_request_1 <= 0)
- abort ();
- inside_process_energize_request_1--;
- if (energize_connection && energize_connection->conn)
- CSkipRequest (energize_connection->conn);
- return Qnil;
- }
-
- static Lisp_Object
- pop_conn (Lisp_Object arg)
- {
- Connection *old_conn = (Connection *) get_opaque_ptr (arg);
- if (! old_conn)
- abort ();
- if (! energize_connection)
- return Qnil;
- if (energize_connection->conn == old_conn)
- abort ();
-
- if (CRequestDelayedP (energize_connection->conn))
- /* We don't call the CWait* functions any more so this shouldn't happen.
- But if it does someday, then we need to either copy the remaining
- bits from new_conn to old_conn, or loop processing requests until
- new_conn is drained.
- */
- abort ();
-
- DeleteConnection (energize_connection->conn);
- energize_connection->conn = old_conn;
-
- return Qnil;
- }
-
- static Lisp_Object
- process_energize_request_1 ()
- {
- Lisp_Object result;
- int speccount = specpdl_depth ();
-
- if (inside_process_energize_request_1)
- {
- /* When the energize process filter is called recursively, push a new
- connection object. The read-pointer of the connection buffer could
- be in the middle of a request. However, we know that the fd itself
- is always pointing between requests. So making a new connection is
- a way of skipping past the one request we were in the process of
- reading when we allowed process output to be handled recursively.
- */
- Connection *old_conn = energize_connection->conn;
- Connection *new_conn =
- make_energize_connection ((void *) energize_connection,
- old_conn->fdin, old_conn->fdout);
- energize_connection->conn = new_conn;
- record_unwind_protect (pop_conn, make_opaque_ptr (old_conn));
- }
-
- /* this must come after pop_conn() to get the right connection object */
- record_unwind_protect (post_handle_request, Qnil);
-
- inside_process_energize_request_1++;
-
- result = process_one_energize_request ();
- notify_delayed_requests ();
-
- /* decrements inside_process_energize_request_1 and possibly replaces
- energize_connection->conn with old_conn.
- */
- unbind_to (speccount, Qnil);
-
- return result;
- }
-
-
- /******** Initialize Energize-related state and set up connection ********/
-
- static void
- setup_connection (Editor *ed, unsigned int id1, unsigned int id2)
- {
- CEditorRequest *req = CWriteEditorRequest (ed->conn, QueryConnectionRType);
-
- /* these 2 slots are ignored */
- req->generic.queryconnection.major = 0;
- req->generic.queryconnection.minor = 0;
-
- req->generic.queryconnection.cadillacId1 = id1;
- req->generic.queryconnection.cadillacId2 = id2;
- req->generic.queryconnection.nProtocols = 1;
- /* first numerical arg is major protocol number, second is minor */
- CWriteProtocol (ed->conn, 0, 10, "editor");
- CWriteLength (ed->conn);
- CWriteRequestBuffer (ed->conn);
- }
-
- /* this is used as the readMethod of the energize connection, so that
- the connection library won't do some buffering that messes us up.
- It does this buffering only if conn->readMethod == read, so using
- another function turns it off.
- */
- static int
- my_read (int fd, char *buf, int nb)
- {
- return read (fd, buf, nb);
- }
-
- static Connection *
- make_energize_connection (Editor *editor, int fdin, int fdout)
- {
- Connection *conn = NewConnection ((void *)editor, fdin, fdout);
- if (conn)
- conn->readMethod = my_read;
- return conn;
- }
-
- DEFUN ("handle-energize-request", Fhandle_energize_request,
- Shandle_energize_request,
- 2, 2, 0,
- "Filter called when a request is available from Energize.")
- (proc, string)
- Lisp_Object proc, string;
- {
- if (!NILP (string))
- CHECK_STRING (string, 0);
-
- if (!energize_connection || !energize_connection->conn)
- {
- /* no need for a message here, Energize is dead */
- return make_number (0);
- }
- if (!energize_connection || (!EQ (energize_connection->proc, proc)))
- {
- message ("Got " IDENTITY_CRISIS " request but not from current connection ");
- return make_number (0);
- }
-
- if (!NILP (string))
- add_in_connection_input_buffer (energize_connection->conn,
- (char *) string_data (XSTRING (string)),
- string_length (XSTRING (string)));
-
- return process_energize_request_1 ();
- }
-
-
- Lisp_Object Venergize_process;
-
- /* Opens a network connection to Energize.
- * server is a string. It can end up with :<uid> or :<username>
- * in which case the uid is added to the TCP port to get the connection */
- static void
- connect_to_energize (char *server_str, char *arg)
- {
- struct Lisp_Process *proc;
- Lisp_Object lp;
- Lisp_Object fil;
- char *host;
- unsigned int port;
- long flags;
- int id1;
- int id2;
-
- if (CGetPortNumber (server_str, &host, &port))
- {
-
- lp = Fopen_network_stream_internal (build_string ("energize"),
- Qnil,
- build_string (host),
- make_number (port));
- if (!NILP (lp))
- {
- int infd, outfd;
- /* Don't ask the user for confirmation when exiting Emacs */
- Fprocess_kill_without_query (lp, Qnil);
- proc = XPROCESS (lp);
- energize_connection = xnew (Editor);
- get_process_file_descriptors (proc, &infd, &outfd);
- energize_connection->conn =
- make_energize_connection (energize_connection, infd, outfd);
- energize_connection->proc = lp;
- energize_connection->binfo_hash = make_hashtable (10);
- energize_connection->image_table = 0;
- energize_connection->gc_save = Qnil;
- energize_connection->major = 0;
- energize_connection->minor = 0;
- peo = allocate_edit_options (10);
- request_serial_number = 0;
- global_reply_wait = 0;
-
- if ((flags = fcntl (energize_connection->conn->fdin, F_GETFL, 0))
- == -1)
- abort ();
-
- #ifdef O_NONBLOCK
- if (fcntl (energize_connection->conn->fdin, F_SETFL,
- flags & ~O_NONBLOCK)
- == -1)
- #else
- if (fcntl (energize_connection->conn->fdin, F_SETFL,
- flags & ~O_NDELAY)
- == -1)
- #endif
- abort ();
-
- XSETSUBR (fil, &Shandle_energize_request);
- set_process_filter (lp, fil, 1);
-
- Venergize_kernel_busy = Qnil;
-
- id1 = 0;
- id2 = 0;
- if (arg)
- sscanf (arg, "%x,%x", &id1, &id2);
-
- Venergize_buffers_list = Qnil;
-
- setup_connection (energize_connection, id1, id2);
-
- Venergize_process = lp;
- }
- else
- error ("couldn't connect to " IDENTITY_CRISIS " server");
- }
- else
- error ("couldn't determine " IDENTITY_CRISIS " server port number");
-
-
- #ifdef ENERGIZE_V2_HEADERS
- if (energize_connection->minor > 9)
- {
- close_energize_connection ();
- error ("This Emacs doesn't understand " IDENTITY_CRISIS " version 3.");
- }
-
- #endif /* ENERGIZE_V2_HEADERS */
-
- }
-
-
- /* Close the connection to energize.
- * Kills all the energize related buffer */
- static void
- close_energize_connection ()
- {
- Editor *ed = energize_connection;
-
- if (ed)
- /* make this function as paranoid as we can */
- {
- /* cleanup the busy state */
- show_all_menubars_busy (False);
- Venergize_kernel_busy = Qnil;
- /* destroy all pop_up boxes */
- lw_destroy_all_pop_ups ();
-
- if (ed->conn)
- DeleteConnection (ed->conn);
- ed->conn = 0;
-
- if (ed->binfo_hash)
- {
- int speccount = specpdl_depth ();
-
- /* we are flushing everything, so we just ignore any change
- hooks and don't make an effort to delete extents since they
- are all going away */
- specbind (Qenergize_buffer_modified_hook, Qnil);
- specbind (Qinhibit_quit, Qt);
- call0 (intern ("de-energize-all-buffers"));
- unbind_to (speccount, Qnil);
-
- free_hashtable (ed->binfo_hash);
- ed->binfo_hash = 0;
- }
-
- /* Do this after de-energize-all-buffers or frame sizes thrash. */
- debuggerpanel_sheet = 0;
- desired_debuggerpanel_exposed_p = 0;
-
- free_edit_options (peo);
-
- if (EQ (ed->proc, Qzero)) abort ();
-
- if (!NILP (ed->proc))
- Fdelete_process (ed->proc);
- ed->proc = Qnil;
-
- Venergize_buffers_list = Qnil;
-
- /* now kill buffers created to satisfy requests on old connection */
- xfree (ed);
- }
-
- /* mark as closed */
- energize_connection = 0;
- Venergize_process = Qnil;
- }
-
-
- DEFUN ("connect-to-energize-internal",
- Fconnect_to_energize_internal, Sconnect_to_energize_internal, 0, 2, 0,
- "Usage: (connect-to-energize-internal <server-name> <energizearg>)\n\
- Energizearg representing two 32 bit Energize ids that will be passed\n\
- to the Energize server when opening the Energize connection.\n\
- Only one connection can be open at a time.")
-
- (server_name, energize_arg)
- Lisp_Object server_name, energize_arg;
- {
- unsigned char *server;
- unsigned char *arg;
-
- if (!NILP (energize_arg))
- {
- CHECK_STRING (energize_arg, 1);
- arg = string_data (XSTRING (energize_arg));
- }
- else
- arg = 0;
-
- if (!NILP (server_name))
- {
- CHECK_STRING (server_name, 1);
- server = string_data (XSTRING (server_name));
- }
- else
- server = 0;
-
- /* since we are going ahead with this, make sure that we are
- really and truly disconnected first */
- Fclose_connection_to_energize ();
-
- connect_to_energize ((char *)server, (char *)arg);
- return Qnil;
- }
-
- DEFUN ("close-connection-to-energize", Fclose_connection_to_energize,
- Sclose_connection_to_energize, 0, 0, 0,
- "Close the open Energize connection, if any.")
- ()
- {
- if (!energize_connection) return Qnil;
-
- close_energize_connection ();
- return Qnil;
- }
-
-
- /* Extents stuff; this used to be in extents.c */
-
- static void
- set_extent_flags (EXTENT extent, Energize_Extent_Data *ext)
- {
- /* clear every flag */
- if (!EXTENT_LIVE_P (extent))
- return;
- extent_start_open_p (extent) = 0;
- extent_end_open_p (extent) = 1;
- extent_read_only_p (extent) = 0;
- extent_highlight_p (extent) = 0;
- extent_unique_p (extent) = 0;
- extent_duplicable_p (extent) = 0;
- extent_invisible_p (extent) = 0;
-
- set_extent_glyph (extent, 0, 0, GL_TEXT);
- set_extent_glyph (extent, 0, 1, GL_TEXT);
-
- if (ext)
- {
- ext->warn_modify = 0;
-
- switch (ext->extentType)
- {
- case CEAttribute:
- break;
-
- case CEAbbreviation:
- break;
-
- case CEWriteProtect:
- extent_read_only_p (extent) = 1;
- break;
-
- case CEGeneric:
- {
- GLYPH begin_glyph = 0; /* always the class glyph */
- GLYPH end_glyph = 0; /* always the instance glyph */
-
- /* if (ext->u.generic.gData->id)
- SET_EXTENT_FLAG (extent, EF_MENU);*/
-
- if (ext->u.generic.gData->glyph)
- end_glyph = ext->u.generic.gData->glyph;
- if (ext->u.generic.gData->cl && ext->u.generic.gData->cl->glyph)
- begin_glyph = ext->u.generic.gData->cl->glyph;
-
- #if 0
- if (begin_glyph && end_glyph)
- {
- begin_glyph = end_glyph;
- end_glyph = 0;
- }
- #endif
-
- if (begin_glyph)
- set_extent_glyph (extent, begin_glyph, 0, GL_TEXT);
- if (end_glyph)
- set_extent_glyph (extent, end_glyph, 1, GL_TEXT);
-
- if (ext->u.generic.gData->cl &&
- (ext->u.generic.gData->cl->flags & CCElectric))
- extent_highlight_p (extent) = 1;
- if (ext->u.generic.gData->cl &&
- (ext->u.generic.gData->cl->flags & CCWarnModified))
- ext->warn_modify = 1;
- #if 0 /* #### some day (soon?)... */
- if (ext->u.generic.gData->cl &&
- (ext->u.generic.gData->cl->flags & CCColumn))
- SET_EXTENT_FLAG (extent, EF_COLUMN);
- #endif
- extent_duplicable_p (extent) = 1;
- extent_unique_p (extent) = 1;
- break;
- }
-
- default:
- break;
- }
- }
- }
-
- extern Lisp_Object Fset_extent_face (Lisp_Object extent, Lisp_Object name);
-
- static void
- set_extent_attributes_index (EXTENT extent, Energize_Extent_Data *ext)
- {
- int graphic_attributes;
-
- if (!ext)
- extent_face_id (extent) = -1;
- else
- {
- switch (ext->extentType)
- {
- case CEAttribute:
- graphic_attributes = ext->u.attr.attrValue;
- break;
-
- case CEGeneric:
- graphic_attributes = ext->u.generic.gData->attribute;
- break;
-
- case CEWriteProtect:
- /* this type has NO display attributes */
- extent_face_id (extent) = -1;
- return;
-
- default:
- graphic_attributes = GA_NO_CHANGE;
- }
-
- if (graphic_attributes >= GA_MAX)
- graphic_attributes = GA_NO_CHANGE;
-
- {
- /* The Venergize_attributes_mapping global is an alist of the form
- ( (<kernel-attribute-number> . <emacs-face-name> ) ... )
- */
- Lisp_Object face = Fcdr (Fassq (make_number (graphic_attributes),
- Venergize_attributes_mapping));
- Lisp_Object e;
- XSETEXTENT (e, extent);
- if (NILP (face))
- message ("Unknown Energize attribute %d", graphic_attributes);
- else if (EQ (face, Qdefault))
- Fset_extent_face (e, Qnil);
- else
- Fset_extent_face (e, face);
- }
- }
- }
-
- void
- restore_energize_extent_state (EXTENT extent)
- {
- Energize_Extent_Data *ext = energize_extent_data (extent);
- if (!ext) return;
- set_extent_flags (extent, ext);
- set_extent_attributes_index (extent, ext);
- }
-
- DEFUN ("extent-to-generic-id", Fextent_to_generic_id, Sextent_to_generic_id,
- 1, 1, 0, "Return Energize ID of buffer of EXTENT.")
- (extent_obj)
- Lisp_Object extent_obj;
- {
- CHECK_EXTENT (extent_obj, 0);
- return word_to_lisp (energize_extent_data_id
- (energize_extent_data (XEXTENT (extent_obj))));
- }
-
-
-
- /* buffer modified routines */
- static void
- send_buffer_modification_state (Editor *editor, BufferInfo *binfo, int flag)
- {
- Connection *conn = editor->conn;
- EId bufferId = binfo->id;
-
- if (conn)
- {
- int state = (flag)?(CMBufferSetModified):(CMBufferSetUnmodified);
- CWriteModifiedBufferHeader (conn, bufferId, state);
- CWriteRequestBuffer (conn);
- }
- }
-
- /* returns 1 if buffer is locked (non-editable),
- 0 if it isn't (editable), and -1 if it can't tell
- */
- static int
- check_buffer_lock (Editor *editor, BufferInfo *binfo)
- {
- Connection *conn = editor->conn;
- struct reply_wait rw;
-
- /* If permision already granted by kernel dont' ask again */
- if (binfo->editable)
- return 0;
-
- /* If can't ask say we do not know */
- if (!conn)
- return -1;
-
- /* Ask the kernel */
- CWriteModifiedBufferHeader (conn, binfo->id, CMBufferQueryLock);
- conn->header->serial = ++request_serial_number;
- CWriteRequestBuffer (conn);
-
- rw.serial = request_serial_number;
- rw.objectId = binfo->id;
- rw.status = -1;
-
- if (!wait_for_reply (&rw))
- return -1;
-
- if (rw.status == CMBufferLocked)
- {
- /* Buffer is locked by kernel so we cannot edit it */
- return 1;
- }
- else if (rw.status == CMBufferUnlocked)
- {
- /* Buffer is unlocked by kernel: edit permission granted! */
- binfo->editable = 1;
- return 0;
- }
- else
- {
- /* This should never happen */
- return -1;
- }
- }
-
-
- /* Ask the kernel if BUFFER is currently locked -- waits for answer */
- static Lisp_Object
- buffer_locked_p (Lisp_Object buffer)
- {
- BufferInfo *binfo;
-
- if (!energize_connection)
- return Qnil;
-
- if (NILP (buffer))
- XSETBUFFER (buffer, current_buffer);
-
- CHECK_BUFFER (buffer, 0);
-
- binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection);
-
- if (!binfo)
- {
- /* Not an Energize buffer, return Qnil: can edit buffer */
- return Qnil;
- }
- else
- {
- /* Energize buffer, check if editable */
- return check_buffer_lock (energize_connection, binfo) == 0 ? Qnil : Qt;
- }
- }
-
-
-
- /* Called by map_extents function called by Fenergize_send_buffer_modified
- */
- static int
- notify_extent_modified (EXTENT extent, void *arg)
- {
- /* arg is a binfo_and_state */
- binfo_and_state *bans = (binfo_and_state*)arg;
- Energize_Extent_Data *ext;
- BufferInfo *binfo = bans->binfo;
- Connection *conn = binfo->editor->conn;
- EId *extent_id;
- Lisp_Object extent_obj;
-
- XSETEXTENT (extent_obj, extent);
- if ((ext = extent_to_data (extent_obj))
- && ext->warn_modify
- && ext->extentType == CEGeneric
- && ext->u.generic.gData
- && ext->u.generic.gData->cl
- && (ext->u.generic.gData->cl->flags & CCWarnModified)
- && ext->u.generic.gData->modified_state != bans->state)
- {
- if (bans->tell_energize)
- {
- CWriteModifiedExtentsHeader (conn, binfo->id, bans->state, 1);
- extent_id = CPut (conn, EId);
- *extent_id = ext->id;
- CWriteLength (conn);
- CWriteRequestBuffer (conn);
- }
- ext->u.generic.gData->modified_state = bans->state;
- }
- return 0;
- }
-
- static int
- ceiwme_lower_mf (EXTENT e, void *arg)
- {
- Lisp_Object extent;
- Energize_Extent_Data *ext;
- XSETEXTENT (extent, e);
- ext = extent_to_data (extent);
- if (ext && ext->warn_modify)
- *((EXTENT *) arg) = e;
- return 0;
- }
-
- static int
- ceiwme_upper_mf (EXTENT e, void *arg)
- {
- Lisp_Object extent;
- Energize_Extent_Data *ext;
- XSETEXTENT (extent, e);
- ext = extent_to_data (extent);
- if (ext && ext->warn_modify)
- {
- *((EXTENT *) arg) = e;
- return 1;
- }
- else
- return 0;
- }
-
- static void
- coerce_endpoints_to_be_inside_warn_on_modify_extents (Bufpos *from_ptr,
- Bufpos *to_ptr,
- struct buffer *b)
- {
- EXTENT lower_extent = 0;
- EXTENT upper_extent = 0;
- Bufpos lower_bound = *from_ptr;
- Bufpos upper_bound = *to_ptr;
- Lisp_Object tmp;
-
- /* make sure that from <= to */
- {
- Bufpos tmp_int = max (lower_bound, upper_bound);
- *from_ptr = lower_bound = min (lower_bound, upper_bound);
- *to_ptr = upper_bound = tmp_int;
- }
-
- if (!BUFFER_NOTIFY_BACKGROUND_BIT_SET_P (b))
- return;
-
- map_extents (BUF_BEG (b), lower_bound, ceiwme_lower_mf,
- (void *) &lower_extent, make_buffer (b), 0, ME_END_CLOSED);
- if (!lower_extent)
- {
- lower_bound = BUF_BEG (b);
- map_extents (upper_bound, BUF_Z (b), ceiwme_upper_mf,
- (void *) &upper_extent, make_buffer (b), 0, ME_END_CLOSED);
- if (!upper_extent)
- upper_bound = BUF_Z (b);
- else
- {
- Bufpos xstart;
- XSETEXTENT (tmp, upper_extent);
- xstart = XINT (Fextent_start_position (tmp));
- upper_bound = max (upper_bound, xstart);
- }
- }
- /* I forget why, but if we found an lower bound, we don't need to find
- an upper bound */
- else
- {
- Bufpos xstart;
- XSETEXTENT (tmp, lower_extent);
- xstart = XINT (Fextent_start_position (tmp));
- lower_bound = min (lower_bound, xstart);
- }
-
- *from_ptr = lower_bound;
- *to_ptr = upper_bound;
- return;
- }
-
- static void
- mark_all_extents_as_unmodified (BufferInfo *binfo)
- {
- binfo_and_state bans;
- bans.binfo = binfo;
- bans.state = FALSE;
- bans.tell_energize = FALSE;
-
- map_extents (BUF_BEG (XBUFFER (binfo->emacs_buffer)),
- BUF_Z (XBUFFER (binfo->emacs_buffer)),
- notify_extent_modified, &bans,
- binfo->emacs_buffer, 0, ME_END_CLOSED);
- }
-
- /* Send the BufferModified events for the current buffer.
- * Handles both global buffer modified and extents modified. */
- DEFUN ("energize-send-buffer-modified", Fenergize_send_buffer_modified,
- Senergize_send_buffer_modified,
- 3, 3, 0,
- "Send a BufferModified request for the current buffer.")
- (state, from, to)
- Lisp_Object state, from, to; /* dont use ANSI arglists in DEFUNs */
- {
- int modifiedp = NILP (state)? 0 : 1;
- Lisp_Object buffer;
- BufferInfo *binfo;
- Bufpos from_int = XINT (from);
- Bufpos to_int = XINT (to);
-
- if (!energize_connection || !energize_connection->conn) return Qnil;
-
- XSETBUFFER (buffer, current_buffer);
-
- Fenergize_barf_if_buffer_locked ();
-
- if (binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection))
- {
- /* now make sure that from and to
- are inside some warn_on_modify extents somewhere */
- coerce_endpoints_to_be_inside_warn_on_modify_extents
- (&from_int, &to_int, current_buffer);
- XSETINT (from, from_int);
- XSETINT (to, to_int);
-
- if (binfo->modified_state != modifiedp)
- {
- send_buffer_modification_state (energize_connection, binfo,
- modifiedp);
- binfo->modified_state = modifiedp;
- }
- #ifndef ENERGIZE_V2_HEADERS
- if (!(binfo->flags & CBFileYourself))
- #endif
- {
- if (modifiedp)
- {
- binfo_and_state bans;
- bans.binfo = binfo;
- bans.state = 1;
- bans.tell_energize = 1;
- map_extents (XINT (from), XINT (to),
- notify_extent_modified, &bans,
- binfo->emacs_buffer, 0,
- ME_END_CLOSED);
- }
- else
- mark_all_extents_as_unmodified (binfo);
- }
- }
- return Qnil;
- }
-
- DEFUN ("energize-barf-if-buffer-locked", Fenergize_barf_if_buffer_locked,
- Senergize_barf_if_buffer_locked, 0, 0, 0,
- "Error if the buffer is locked.")
- ()
- {
- Lisp_Object buffer;
- XSETBUFFER (buffer, current_buffer);
-
- if (!energize_connection || !energize_connection->conn)
- return Qnil;
-
- while (!NILP (buffer_locked_p (buffer)))
- {
- notify_delayed_requests ();
- Fsignal (Qbuffer_locked_by_energize, (Fcons (buffer, Qnil)));
- }
- return Qnil;
- }
-
-
- DEFUN ("energize-send-region", Fenergize_send_region,
- Senergize_send_region,
- 2, 2, 0,
- "Send region as user input")
- (start, end)
- Lisp_Object start, end;
- {
- BufferInfo *binfo;
- Lisp_Object b;
- CEditorRequest *req;
-
- if (!energize_connection || !energize_connection->conn)
- error ("Not connected to " IDENTITY_CRISIS);
-
- XSETBUFFER (b, current_buffer);
- if (binfo = get_buffer_info_for_emacs_buffer (b, energize_connection))
- {
- Bufpos st, en;
- Bufpos ceil;
-
- get_bufrange (current_buffer, start, end, &st, &en);
-
- do
- {
- ceil = BUF_CEILING_OF (current_buffer, st);
-
- req = CWriteEditorRequest (energize_connection->conn,
- UserTypedSomethingRType);
- req->usertypedsomething.bufferId = binfo->id;
- CWriteVstringLen
- (energize_connection->conn,
- (char *) BUF_BYTE_ADDRESS (current_buffer, st), ceil - st);
- CWriteLength (energize_connection->conn);
- CWriteRequestBuffer (energize_connection->conn);
- st = ceil;
- } while (st < en);
- return Qnil;
- }
- return Qnil;
- }
-
- DEFUN ("connected-to-energize-p", Fconnected_to_energize_p,
- Sconnected_to_energize_p,
- 0, 0, 0,
- "Return nil if no connection to Energize.")
- ()
- {
- if (!energize_connection ||
- !energize_connection->conn ||
- !energize_connection->binfo_hash ||
- !PROCESSP (energize_connection->proc))
- return Qnil;
- else
- return Qt;
- }
-
- DEFUN ("energize-user-input-buffer-mark", Fenergize_user_input_buffer_mark,
- Senergize_user_input_buffer_mark, 0, 1, 0,
- "Return the mark associated to the given Energize buffer.")
- (buffer)
- Lisp_Object buffer;
- {
- BufferInfo *binfo;
-
- XSETBUFFER (buffer, decode_buffer (buffer, 0));
- if (!energize_connection) return Qnil;
- if ((binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection)))
- return binfo->output_mark;
- else
- return Qnil;
- }
-
- Lisp_Object
- energize_get_buffer_process (Lisp_Object buf)
- {
- BufferInfo *binfo;
-
- if (!BUFFERP (buf)) return Qnil;
- if (!energize_connection) return Qnil;
- binfo = get_buffer_info_for_emacs_buffer (buf, energize_connection);
- if (!binfo) return Qnil;
- if (! binfo->buffer_type) return Qnil;
- if (!strcmp (binfo->buffer_type, "energize-debugger-buffer") ||
- !strcmp (binfo->buffer_type, "energize-log-file-buffer"))
- return Venergize_process;
- return Qnil;
- }
-
-
- static int
- get_energize_connection_and_buffer_id (Lisp_Object buffer, void **conn_ptr,
- long *buffer_id_ptr)
- {
- BufferInfo *binfo;
-
- if (!energize_connection || !energize_connection->conn) return 0;
-
- binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection);
-
- *conn_ptr = (void *) energize_connection->conn;
- *buffer_id_ptr = (long) binfo ? binfo->id : 0;
- return 1;
- }
-
- static int
- get_energize_connection_and_current_buffer_id (void **conn_ptr,
- long *buffer_id_ptr)
- {
- Lisp_Object lisp_buffer;
- XSETBUFFER (lisp_buffer, current_buffer);
-
- return get_energize_connection_and_buffer_id (lisp_buffer, conn_ptr,
- buffer_id_ptr);
- }
-
- int *
- get_psheets_for_buffer (Lisp_Object buffer, int *count_ptr)
- {
- BufferInfo *binfo;
-
- if (!energize_connection || !energize_connection->conn) return 0;
-
- binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection);
- if (!binfo) return 0;
-
- if (count_ptr) *count_ptr = binfo->n_p_sheets;
- return binfo->p_sheet_ids;
- }
-
- void
- notify_energize_sheet_hidden (EId id)
- {
- EId buffer_id = buffer_id_of_sheet (id);
- if (!buffer_id)
- return;
-
- if (buffer_id && energize_connection && energize_connection->conn)
- {
- CWriteSheetRequest (energize_connection->conn,
- CSHide, id, buffer_id, "");
- CWriteRequestBuffer (energize_connection->conn);
- }
- }
-
- DEFUN ("energize-query-buffer", Fenergize_query_buffer,
- Senergize_query_buffer, 1, 2, 0,
- "Ask Energize to create a buffer containing the file filename.\n\
- Returns the buffer or NIL if Energize cannot create the buffer.\n\
- If second argument just-ask is T, just ask if Energize\n\
- already knows about the file and returns T if yes, NIL otherwise.")
- (filename, just_ask)
- Lisp_Object filename, just_ask;
- {
- struct Lisp_String *filename_str;
- CEditorRequest *creq;
- char *dir_sep;
- struct reply_wait rw;
-
- if (!energize_connection || !energize_connection->conn)
- return Qnil;
-
- filename = Fexpand_file_name (filename, Qnil);
- filename_str = XSTRING (filename);
-
- dir_sep = (char *) strrchr ((char *) string_data (filename_str), '/');
-
- creq = CWriteEditorRequest (energize_connection->conn, QueryBufferRType);
- creq->head.data = !NILP (just_ask);
- creq->head.serial = ++request_serial_number;
- CWriteVstringLen (energize_connection->conn, (char *) string_data (filename_str),
- (dir_sep)? (dir_sep - (char *) string_data (filename_str)): 0);
- CWriteVstringLen (energize_connection->conn,
- (char *) string_data (filename_str), string_length (filename_str));
- CWriteLength (energize_connection->conn);
- CWriteRequestBuffer (energize_connection->conn);
-
- rw.serial = request_serial_number;
- rw.objectId = 0;
-
- if (!wait_for_reply (&rw))
- return Qnil;
-
- if (rw.status)
- {
- if (rw.objectId)
- {
- BufferInfo* binfo = get_buffer_info_for_id (rw.objectId,
- energize_connection);
- return binfo ? binfo->emacs_buffer : Qt;
- }
- else
- return Qt;
- }
- else
- return Qnil;
- }
-
-
- DEFUN ("energize-protocol-level", Fenergize_protocol_level,
- Senergize_protocol_level, 0, 0, 0,
- "Return the Energize protocol level.")
- ()
- {
- return
- energize_connection
- ? Fcons (make_number (energize_connection->major),
- make_number (energize_connection->minor))
- : Qnil;
- }
-
-
- DEFUN ("energize-psheets-visible-p", Fenergize_psheets_visible_p,
- Senergize_psheets_visible_p, 0, 1, 0,
- "Whether the (optional) frame currently has open psheets.")
- (frame)
- Lisp_Object frame;
- {
- if (NILP (frame))
- XSETFRAME (frame, XFRAME(Fselected_frame(Qnil)));
- CHECK_FRAME (frame, 0);
- if (FRAME_X_CURRENT_PSHEETS (XFRAME (frame)))
- return Qt;
- return Qnil;
- }
-
- DEFUN ("energize-buffer-has-psheets-p", Fenergize_buffer_has_psheets_p,
- Senergize_buffer_has_psheets_p, 0, 1, 0,
- "Whether the buffer has psheets associated with it.")
- (buf)
- Lisp_Object buf;
- {
- int count;
- if (NILP (buf))
- buf = Fcurrent_buffer ();
- CHECK_BUFFER (buf, 0);
- if (get_psheets_for_buffer (buf, &count))
- return Qt;
- return Qnil;
- }
-
-
- void
- make_psheets_desired (struct frame *f, Lisp_Object buffer)
- {
- int count;
- int *psheets;
-
- if (NILP (buffer) || !(psheets = get_psheets_for_buffer (buffer, &count)))
- {
- FRAME_X_DESIRED_PSHEETS (f) = 0;
- FRAME_X_DESIRED_PSHEET_COUNT (f) = 0;
- FRAME_X_DESIRED_PSHEET_BUFFER (f) = Qnil;
- }
- else
- {
- /* Do not show the debugger panel in this function. The
- * debugger panel should never be listed in the visible psheets. */
- extern int debuggerpanel_sheet;
-
- if (count == 1 && psheets [0] == debuggerpanel_sheet)
- return;
-
- FRAME_X_DESIRED_PSHEETS (f) = psheets;
- FRAME_X_DESIRED_PSHEET_COUNT (f) = count;
- FRAME_X_DESIRED_PSHEET_BUFFER (f) = buffer;
- }
-
- /* Garbage the frame so that the sheets get recomputed right away and not
- the next time some display change happens. Possibly redisplay should
- notice this on its own without the garbaged flag. But once redisplay
- gets smarter about such things, all garbagers should be revisited.
- */
- MARK_FRAME_CHANGED (f);
- }
-
- Lisp_Object
- desired_psheet_buffer (struct frame *f)
- {
- if (FRAME_IS_X (f))
- return FRAME_X_DESIRED_PSHEET_BUFFER (f);
- else
- return Qnil;
- }
-
- /* This function is invoked when the user clicks on the "sheet" button.
- */
- DEFUN ("energize-toggle-psheet", Fenergize_toggle_psheet,
- Senergize_toggle_psheet, 0, 0, "",
- "")
- ()
- {
- struct frame *frame = XFRAME(Fselected_frame(Qnil));
- Lisp_Object buffer = Fwindow_buffer (Fselected_window (Qnil));
- if (EQ (buffer, desired_psheet_buffer (frame)))
- make_psheets_desired (frame, Qnil);
- else
- make_psheets_desired (frame, buffer);
- return Qnil;
- }
-
-
- static void energize_show_menubar_of_buffer (Lisp_Object frame,
- Lisp_Object buffer,
- Lisp_Object psheets_too);
-
- /* This is called when a buffer becomes visible in some window.
-
- Show the menubar associated with this buffer, and show the psheets as
- well if this buffer is the last buffer whose psheets were visible in
- this frame.
- */
- void
- energize_buffer_shown_hook (struct window *window)
- {
- struct frame* frame = XFRAME (window->frame);
- Lisp_Object buffer = window->buffer;
- Lisp_Object pbuf;
-
- if (! FRAME_IS_X (frame)) return;
- pbuf = desired_psheet_buffer (frame);
-
- if (!MINI_WINDOW_P (window))
- energize_show_menubar_of_buffer (window->frame, buffer,
- (EQ (buffer, pbuf) ? Qt : Qnil));
- }
-
-
- static int
- find_buffer_in_different_window (window, buffer, not_in)
- struct window* window;
- Lisp_Object buffer;
- struct window* not_in;
- {
- Lisp_Object child;
- if (!NILP (window->buffer))
- {
- /* a leaf window */
- return (EQ (window->buffer, buffer) && (window != not_in));
- }
- else
- {
- /* a non leaf window, visit either the hchild or the vchild */
- for (child = !NILP (window->vchild) ? window->vchild : window->hchild;
- !NILP (child);
- child = XWINDOW (child)->next)
- {
- if (find_buffer_in_different_window (XWINDOW (child), buffer,
- not_in))
- return 1;
- }
- return 0;
- }
- }
-
- /* returns 1 if the buffer is only visible in window on frame f */
- static int
- buffer_only_visible_in_this_window_p (Lisp_Object buffer,
- struct frame* f,
- struct window* window)
- {
- return !find_buffer_in_different_window (XWINDOW (f->root_window), buffer,
- window);
- }
-
- /* This is called just before a buffer which is visible becomes invisible,
- either because some other buffer is about to be made visible in its window,
- or because that window is being deleted.
-
- If this buffer's psheets are visible, hide them.
- */
- void
- energize_buffer_hidden_hook (struct window *window)
- {
- struct frame *f = XFRAME (window->frame);
-
- if (! FRAME_IS_X (f)) return;
-
- /* hides the p_sheet if we are changing the buffer of the
- * selected window of the frame and the p_sheet where displayed */
- if (EQ (window->buffer, desired_psheet_buffer (f))
- && buffer_only_visible_in_this_window_p (window->buffer, f, window))
- make_psheets_desired (f, Qnil);
- }
-
-
- /* This is called just before the selected window is no longer the selected
- window because some other window is being selected. The given window is
- not being deleted, it is merely no longer the selected one.
-
- This doesn't do anything right now.
- */
- void
- energize_window_deselected_hook (struct window *window)
- {
- }
-
-
- /* This is called just after a window has been selected.
-
- Show the menubar associated with this buffer; leave the psheets as
- they are.
- */
- void
- energize_window_selected_hook (struct window *window)
- {
- struct frame* frame = XFRAME (window->frame);
- Lisp_Object buffer = window->buffer;
-
- if (FRAME_IS_X (frame) && !MINI_WINDOW_P (window))
- energize_show_menubar_of_buffer (window->frame, buffer, Qnil);
- }
-
-
-
- int current_debuggerpanel_exposed_p;
- int desired_debuggerpanel_exposed_p;
- int debuggerpanel_sheet;
-
- static void
- energize_show_menubar_of_buffer (Lisp_Object frame,
- Lisp_Object buffer,
- Lisp_Object psheets_too)
- {
- struct frame *f;
-
- if (NILP (frame))
- f = XFRAME (Fselected_frame (Qnil));
- else {
- CHECK_FRAME (frame, 0);
- f = XFRAME (frame);
- }
-
- if (! FRAME_IS_X (f)) error ("not an X frame");
-
- if (! NILP (psheets_too))
- {
- Lisp_Object buffer;
- XSETBUFFER (buffer, current_buffer);
- make_psheets_desired (f, buffer);
- }
- }
-
-
- /* edit-mode dialog box
- This stuff really sucks
- */
-
- static struct editmode {
- int ok, external, view, edit, window, split;
- char *other;
- } editmode;
-
- static void
- edit_mode_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
- {
- widget_value *data;
- char *name = (char *) client_data;
-
- if ((int) client_data == -1) name = "cancel"; /* WM_DELETE_WINDOW */
-
- if (!strcmp (XtName (widget), "otherText")) /* screw it */
- ;
- else if (!strcmp (name, "externalBox"))
- {
- /* make the text slot be active only if "other" is selected */
- data = malloc_widget_value ();
- data->name = "externalOther";
- if (! lw_get_some_values (id, data)) abort ();
- data->enabled = data->selected;
- data->name = "otherText";
- lw_modify_all_widgets (id, data, True);
- free_widget_value (data);
- }
- else if (!strcmp (name, "cancel"))
- {
- editmode.ok = -1;
- lw_destroy_all_widgets (id);
- }
- else if (!strcmp (name, "help"))
- {
- Lisp_Object v = Fmake_vector (make_number (3), Qt);
- vector_data (XVECTOR (v)) [0] = build_string ("ok");
- vector_data (XVECTOR (v)) [1] = list1 (Qignore);
- Fpopup_dialog_box (list2 (build_string ("dbx_editmode_help"), v));
- }
- else if (!strcmp (name, "ok"))
- {
- editmode.ok = 1;
- data = malloc_widget_value ();
- data->name = "externalEmacs";
- if (! lw_get_some_values (id, data)) abort ();
- if (data->selected) editmode.external = 0;
- data->name = "externalViXterm";
- if (! lw_get_some_values (id, data)) abort ();
- if (data->selected) editmode.external = 1;
- data->name = "externalViCmdtool";
- if (! lw_get_some_values (id, data)) abort ();
- if (data->selected) editmode.external = 2;
- data->name = "externalOther";
- if (! lw_get_some_values (id, data)) abort ();
- if (data->selected) editmode.external = 3;
- data->name = "otherText";
- if (! lw_get_some_values (id, data)) abort ();
- editmode.other = data->value;
-
- data->name = "emacsView";
- if (! lw_get_some_values (id, data)) abort ();
- if (data->selected) editmode.view = 0;
- data->name = "viView";
- if (! lw_get_some_values (id, data)) abort ();
- if (data->selected) editmode.view = 1;
- data->name = "lessView";
- if (! lw_get_some_values (id, data)) abort ();
- if (data->selected) editmode.view = 2;
-
- data->name = "editEmacs";
- if (! lw_get_some_values (id, data)) abort ();
- if (data->selected) editmode.edit = 0;
- data->name = "editVi";
- if (! lw_get_some_values (id, data)) abort ();
- if (data->selected) editmode.edit = 1;
-
- data->name = "windowOne";
- if (! lw_get_some_values (id, data)) abort ();
- if (data->selected) editmode.window = 0;
- data->name = "windowSeveral";
- if (! lw_get_some_values (id, data)) abort ();
- if (data->selected) editmode.window = 1;
- data->name = "windowMany";
- if (! lw_get_some_values (id, data)) abort ();
- if (data->selected) editmode.window = 2;
-
- data->name = "splitScreens";
- if (! lw_get_some_values (id, data)) abort ();
- editmode.split = !!data->selected;
-
- free_widget_value (data);
- lw_destroy_all_widgets (id);
- }
- else
- {
- abort ();
- }
- }
-
- static int
- editmode_done (void *arg)
- {
- return (editmode.ok != 0);
- }
-
- extern LWLIB_ID new_lwlib_id (void);
-
- DEFUN ("energize-edit-mode-prompt", Fenergize_edit_mode_prompt,
- Senergize_edit_mode_prompt, 6, 6, 0, "")
- (external, edit_mode, view_mode, other_text, window, split)
- Lisp_Object external, edit_mode, view_mode, other_text, window, split;
- {
- int dbox_id;
- struct frame *f = XFRAME(Fselected_frame(Qnil));
- widget_value *data;
- Widget parent, dbox;
-
- if (!FRAME_IS_X (f)) error ("not an X frame");
- parent = FRAME_X_SHELL_WIDGET (f);
-
- CHECK_INT (external, 0);
- CHECK_INT (edit_mode, 0);
- CHECK_INT (view_mode, 0);
- CHECK_INT (window, 0);
- CHECK_INT (split, 0);
- CHECK_STRING (other_text, 0);
-
- editmode.ok = 0;
- editmode.external = XINT (external);
- editmode.view = XINT (view_mode);
- editmode.edit = XINT (edit_mode);
- editmode.window = XINT (window);
- editmode.split = XINT (split);
- editmode.other = 0;
-
- data = malloc_widget_value ();
- data->name = "editmode";
- data->value = "editmode";
- data->enabled = 1;
-
- dbox_id = new_lwlib_id ();
- dbox = lw_create_widget ("editmode", "editmode", dbox_id, data, parent,
- 1, 0, edit_mode_callback, 0);
- data->value = 0;
-
- data->name = "button1"; data->call_data = data->value = "ok";
- lw_modify_all_widgets (dbox_id, data, True);
- data->name = "button2"; data->call_data = data->value = "cancel";
- lw_modify_all_widgets (dbox_id, data, True);
- data->name = "button3"; data->call_data = data->value = "help";
- lw_modify_all_widgets (dbox_id, data, True);
- data->name = data->call_data = "externalBox";
- lw_modify_all_widgets (dbox_id, data, True);
- data->name = "otherText"; data->call_data = "otherText";
- lw_modify_all_widgets (dbox_id, data, True);
- data->name = "message"; data->value = "editmode";
- lw_modify_all_widgets (dbox_id, data, True);
-
- data->selected = 1;
- switch (editmode.external)
- {
- case 0: data->name = "externalEmacs"; break;
- case 1: data->name = "externalViXterm"; break;
- case 2: data->name = "externalViCmdtool"; break;
- case 3: data->name = "externalOther"; break;
- default: abort ();
- }
- lw_modify_all_widgets (dbox_id, data, True);
- switch (editmode.view)
- {
- case 0: data->name = "emacsView"; break;
- case 1: data->name = "viView"; break;
- case 2: data->name = "lessView"; break;
- default: abort ();
- }
- lw_modify_all_widgets (dbox_id, data, True);
- switch (editmode.edit)
- {
- case 0: data->name = "editEmacs"; break;
- case 1: data->name = "editVi"; break;
- default: abort ();
- }
- lw_modify_all_widgets (dbox_id, data, True);
- switch (editmode.window)
- {
- case 0: data->name = "windowOne"; break;
- case 1: data->name = "windowSeveral"; break;
- case 2: data->name = "windowMany"; break;
- default: abort ();
- }
- lw_modify_all_widgets (dbox_id, data, True);
-
- data->name = "otherText";
- data->selected = 0;
- data->value = (char *) string_data (XSTRING (other_text));
- data->enabled = (editmode.external == 3);
- lw_modify_all_widgets (dbox_id, data, True);
-
- data->name = "splitScreens";
- data->enabled = 1;
- data->selected = editmode.split;
- data->value = 0;
- lw_modify_all_widgets (dbox_id, data, True);
-
- free_widget_value (data);
-
- lw_pop_up_all_widgets (dbox_id);
-
- wait_delaying_user_input (editmode_done, 0);
-
- if (editmode.ok == -1)
- return Fcons (external,
- list5 (edit_mode, view_mode, other_text, window, split));
- else if (editmode.ok == 1)
- return Fcons (make_number (editmode.external),
- list5 (make_number (editmode.view),
- make_number (editmode.edit),
- build_string (editmode.other ? editmode.other : ""),
- make_number (editmode.window),
- make_number (editmode.split)));
- else
- abort ();
- }
-
- static LWLIB_ID search_id;
- static int last_search_up_p;
-
- static void
- hide_search_dialog (Widget w, LWLIB_ID id)
- {
- #if 0
- /* I'd like to do this, but the widget occasionally gets FUCKED */
- XUnmapWindow (XtDisplay (w), XtWindow (w));
- #else
- lw_destroy_all_widgets (id);
- #endif
- }
-
-
- static void
- search_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
- {
- Widget parent = widget;
- widget_value *data;
- char *name = (char *) client_data;
- Lisp_Object search, replace;
- Lisp_Object case_sensitive_p, regexp_p, direction, match_word_p;
-
- if ((int) client_data == -1) name = "done"; /* WM_DELETE_WINDOW */
-
- while (parent && XtClass (parent) != xmDialogShellWidgetClass)
- parent = XtParent (parent);
- if (! parent) abort ();
-
- if (!strcmp (name, "done"))
- {
- hide_search_dialog (parent, id);
- return;
- }
- #if 0
- else if (!strcmp (name, "help"))
- {
- Lisp_Object v = Fmake_vector (3, Qt);
- vector_data (XVECTOR (v)) [0] = build_string ("ok");
- vector_data (XVECTOR (v)) [1] = list1 (Qignore);
- Fpopup_dialog_box (list2 (build_string ("dbx_search_help"), v));
- return;
- }
- #endif
-
- {
- struct device *d = get_device_from_display (XtDisplay (widget));
- DEVICE_X_MOUSE_TIMESTAMP (d) = DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d);
- }
-
- if (!strcmp (name, "gotoStart"))
- {
- signal_special_Xt_user_event (Qcall_interactively, Qbeginning_of_buffer);
- }
- else if (!strcmp (name, "gotoEnd"))
- {
- signal_special_Xt_user_event (Qcall_interactively, Qend_of_buffer);
- }
- else if (!strcmp (name, "scrollForward"))
- {
- signal_special_Xt_user_event (Qcall_interactively, Qscroll_up);
- }
- else if (!strcmp (name, "scrollBack"))
- {
- signal_special_Xt_user_event (Qcall_interactively, Qdown_up);
- }
- else
- {
- data = malloc_widget_value ();
- data->name = "searchText";
- if (! lw_get_some_values (id, data)) abort ();
- search = build_string (data->value);
- data->name = "replaceText";
- if (! lw_get_some_values (id, data)) abort ();
- replace = build_string (data->value);
- data->name = "regexpSearch";
- if (! lw_get_some_values (id, data)) abort ();
- regexp_p = (data->selected ? Qt : Qnil);
- data->name = "caseSearch";
- if (! lw_get_some_values (id, data)) abort ();
- case_sensitive_p = (data->selected ? Qt : Qnil);
- data->name = "matchWord";
- if (! lw_get_some_values (id, data)) abort ();
- match_word_p = (data->selected ? Qt : Qnil);
-
- data->name = "directionForward";
- if (! lw_get_some_values (id, data)) abort ();
- direction = data->selected ? Qt : Qnil;
-
- if (!strcmp (name, "search"))
- replace = Qnil;
- else if (!strcmp (name, "replace"))
- ;
- else if (!strcmp (name, "replace_all"))
- {
- replace = list1 (replace);
- /* hide_search_dialog (parent, id); */
- }
- else
- abort ();
-
- free_widget_value (data);
-
- signal_special_Xt_user_event (intern ("energize-search-internal"),
- (NILP (replace)
- ? list5 (case_sensitive_p, match_word_p,
- regexp_p, direction, search)
- : list6 (case_sensitive_p, match_word_p,
- regexp_p, direction, search,
- replace)));
- }
- }
-
-
- DEFUN ("energize-search", Fenergize_search, Senergize_search, 0, 0, "",
- "Pop up the search-and-replace dialog box.")
- ()
- {
- int dbox_id;
- struct frame *f = XFRAME (Fselected_frame (Qnil));
- widget_value *data;
- Widget parent, dbox;
-
- if (!FRAME_IS_X (f)) error ("not an X frame");
- parent = FRAME_X_SHELL_WIDGET (f);
-
- data = malloc_widget_value ();
-
- dbox_id = (search_id ? search_id : new_lwlib_id());
- dbox = lw_create_widget ("search", "search", dbox_id, NULL, parent,
- 1, 0, search_callback, 0);
- data->enabled = 1;
- data->value = 0;
-
- data->name = "button1"; data->value = data->call_data = "search";
- lw_modify_all_widgets (dbox_id, data, True);
- data->name = "button2"; data->value = data->call_data = "replace";
- lw_modify_all_widgets (dbox_id, data, True);
- data->name = "button3"; data->value = data->call_data = "replace_all";
- lw_modify_all_widgets (dbox_id, data, True);
- data->name = "button4"; data->value = data->call_data = "done";
- lw_modify_all_widgets (dbox_id, data, True);
-
- data->value = 0;
- data->name = data->call_data = "gotoStart";
- lw_modify_all_widgets (dbox_id, data, True);
- data->name = data->call_data = "gotoEnd";
- lw_modify_all_widgets (dbox_id, data, True);
- data->name = data->call_data = "scrollBack";
- lw_modify_all_widgets (dbox_id, data, True);
- data->name = data->call_data = "scrollForward";
- lw_modify_all_widgets (dbox_id, data, True);
-
- data->value = 0;
- data->name = data->call_data = "caseSearch";
- data->selected = NILP (current_buffer->case_fold_search);
- lw_modify_all_widgets (dbox_id, data, True);
-
- data->name = data->call_data = "directionForward";
- data->selected = 1;
- lw_modify_all_widgets (dbox_id, data, True);
- data->name = data->call_data = "directionBackward";
- data->selected = 0;
- lw_modify_all_widgets (dbox_id, data, True);
-
- free_widget_value (data);
-
- lw_pop_up_all_widgets (dbox_id);
- last_search_up_p = 0;
- if (search_id)
- {
- Widget w = lw_get_widget (dbox_id, parent, True);
- if (! w) abort ();
- XMapRaised (XtDisplay (w), XtWindow (w));
- }
- else
- {
- search_id = dbox_id;
- }
-
- return Qnil;
- }
-
-
-
- /*************** Definition of Emacs Lisp-callable functions ***************/
-
- void
- syms_of_energize (void)
- {
- defsubr (&Senergize_send_buffer_modified);
- defsubr (&Senergize_list_menu);
- defsubr (&Senergize_execute_menu_item);
- defsubr (&Senergize_execute_command_internal);
- defsubr (&Sconnect_to_energize_internal);
- defsubr (&Sconnected_to_energize_p);
- defsubr (&Sclose_connection_to_energize);
- defsubr (&Shandle_energize_request);
- defsubr (&Senergize_buffer_p);
- defsubr (&Senergize_buffer_type);
- defsubr (&Sset_energize_buffer_type_internal);
- defsubr (&Senergize_buffer_id);
- defsubr (&Senergize_request_kill_buffer);
- defsubr (&Senergize_send_region);
- defsubr (&Senergize_user_input_buffer_mark);
- defsubr (&Senergize_update_menubar);
- defsubr (&Senergize_extent_menu_p);
- defsubr (&Senergize_query_buffer);
- defsubr (&Senergize_barf_if_buffer_locked);
- defsubr (&Senergize_psheets_visible_p);
- defsubr (&Senergize_buffer_has_psheets_p);
- defsubr (&Senergize_toggle_psheet);
- defsubr (&Senergize_protocol_level);
- defsubr (&Senergize_edit_mode_prompt);
- defsubr (&Senergize_search);
- defsubr (&Sextent_to_generic_id);
-
- defsymbol (&Qenergize_create_buffer_hook, "energize-create-buffer-hook");
- defsymbol (&Qenergize_buffer_modified_hook, "energize-buffer-modified-hook");
-
- defsymbol (&Qenergize_kernel_busy, "energize-kernel-busy");
-
- defsymbol (&Qenergize_kernel_busy_hook, "energize-kernel-busy-hook");
- defsymbol (&Qenergize_menu_update_hook, "energize-menu-update-hook");
- defsymbol (&Qbuffer_locked_by_energize, "buffer-locked-by-energize");
- defsymbol (&Qenergize_user_input_buffer_mark,
- "energize-user-input-buffer-mark");
- defsymbol (&Qenergize_make_many_buffers_visible,
- "energize-make-many-buffers-visible");
- defsymbol (&Qenergize, "energize");
- defsymbol (&Qenergize_auto_revert_buffer, "energize-auto-revert-buffer");
- }
-
- void
- vars_of_energize (void)
- {
- energize_connection = 0;
- inside_process_energize_request_1 = 0;
-
- staticpro (&Venergize_buffers_list);
- Venergize_buffers_list = Qnil;
-
- staticpro (&Vall_energize_pixmaps);
- Vall_energize_pixmaps = Qnil;
-
- Fprovide (intern ("energize"));
-
- search_id = 0;
-
- DEFVAR_LISP ("energize-process", &Venergize_process,
- "The Lisp object representing the Energize connection, or nil");
- Venergize_process = Qnil;
-
- DEFVAR_LISP ("energize-create-buffer-hook", &Venergize_create_buffer_hook,
- "Hook called when buffer is created by energize; takes \n\
- BUFFER as its only argument.");
- Venergize_create_buffer_hook = Qnil;
-
-
- DEFVAR_LISP ("energize-kernel-modification-hook",
- &Venergize_kernel_modification_hook,
- "Hook called when a buffer is being modified by energize;\n\
- takes no arguments.");
- Venergize_kernel_modification_hook = Qnil;
-
- DEFVAR_BOOL ("ignore-kernel",
- &ignore_kernel,
- "Set when the kernel should be ignored -- for debugging.");
- ignore_kernel = 0;
-
- DEFVAR_LISP ("energize-kernel-busy", &Venergize_kernel_busy,
- "True if the Energize kernel is busy.");
- Venergize_kernel_busy = Qnil;
- DEFVAR_LISP ("energize-kernel-busy-hook", &Venergize_kernel_busy_hook,
- "Hook called when the Energize kernel becomes busy or non busy.");
- Venergize_kernel_busy_hook = Qnil;
-
- DEFVAR_LISP ("energize-menu-update-hook", &Venergize_menu_update_hook,
- "Hook called when the Energize kernel updates the menubar.");
- Venergize_menu_update_hook = Qnil;
-
- DEFVAR_LISP ("energize-attributes-mapping", &Venergize_attributes_mapping,
- "A-list to map kernel attributes indexes to Emacs attributes");
- Venergize_attributes_mapping = Qnil;
-
- DEFVAR_INT ("energize-extent-gc-threshold", &energize_extent_gc_threshold,
- "Number of extents in a ModifyBuffer request above which to do a GC");
- energize_extent_gc_threshold = 20;
-
- pure_put (Qbuffer_locked_by_energize, Qerror_conditions,
- list2 (Qbuffer_locked_by_energize, Qerror));
- pure_put (Qbuffer_locked_by_energize, Qerror_message,
- build_string ("Buffer is currently locked by kernel"));
- }
-
- void
- complex_vars_of_energize (void)
- {
- image_cache = make_strings_hashtable (50);
- }
-
- #endif /* ENERGIZE */
-